From bbe7d1ea6c46baa6e997d09c91708dda00ded036 Mon Sep 17 00:00:00 2001 From: Niktia Date: Sun, 30 Nov 2025 19:49:37 +0700 Subject: [PATCH] init --- src/main/java/com/example/nto/App.java | 5 ++ .../Exception/BookingConflictException.java | 7 ++ .../Exception/EmployeeNotFoundException.java | 7 ++ .../nto/Exception/GlobalExceptionHandler.java | 30 +++++++ .../nto/Exception/PlaceNotFoundException.java | 7 ++ .../nto/controller/BookingController.java | 49 ++++++++++++ .../nto/controller/EmployeeController.java | 50 ++++++++++++ .../java/com/example/nto/entity/Booking.java | 21 ++--- .../java/com/example/nto/entity/Employee.java | 9 ++- .../java/com/example/nto/entity/Place.java | 14 ++-- .../nto/repository/BookingRepository.java | 18 ++++- .../nto/repository/EmployeeRepository.java | 12 ++- .../nto/repository/PlaceRepository.java | 9 ++- .../example/nto/service/BookingService.java | 9 +++ .../example/nto/service/EmployeeService.java | 8 +- .../nto/service/impl/BookingServiceImpl.java | 78 +++++++++++++++++++ .../nto/service/impl/EmployeeServiceImpl.java | 13 ++++ 17 files changed, 322 insertions(+), 24 deletions(-) create mode 100644 src/main/java/com/example/nto/Exception/BookingConflictException.java create mode 100644 src/main/java/com/example/nto/Exception/EmployeeNotFoundException.java create mode 100644 src/main/java/com/example/nto/Exception/GlobalExceptionHandler.java create mode 100644 src/main/java/com/example/nto/Exception/PlaceNotFoundException.java diff --git a/src/main/java/com/example/nto/App.java b/src/main/java/com/example/nto/App.java index e453f89..e5435c1 100644 --- a/src/main/java/com/example/nto/App.java +++ b/src/main/java/com/example/nto/App.java @@ -1,12 +1,17 @@ package com.example.nto; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@SpringBootApplication public class App { public static void main(String[] args) { + SpringApplication.run(App.class, args); } } diff --git a/src/main/java/com/example/nto/Exception/BookingConflictException.java b/src/main/java/com/example/nto/Exception/BookingConflictException.java new file mode 100644 index 0000000..6dfd5f0 --- /dev/null +++ b/src/main/java/com/example/nto/Exception/BookingConflictException.java @@ -0,0 +1,7 @@ +package com.example.nto.Exception; + +public class BookingConflictException extends RuntimeException { + public BookingConflictException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/nto/Exception/EmployeeNotFoundException.java b/src/main/java/com/example/nto/Exception/EmployeeNotFoundException.java new file mode 100644 index 0000000..051c372 --- /dev/null +++ b/src/main/java/com/example/nto/Exception/EmployeeNotFoundException.java @@ -0,0 +1,7 @@ +package com.example.nto.Exception; + +public class EmployeeNotFoundException extends RuntimeException { + public EmployeeNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/nto/Exception/GlobalExceptionHandler.java b/src/main/java/com/example/nto/Exception/GlobalExceptionHandler.java new file mode 100644 index 0000000..b78124c --- /dev/null +++ b/src/main/java/com/example/nto/Exception/GlobalExceptionHandler.java @@ -0,0 +1,30 @@ +package com.example.nto.Exception; + +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +@RestControllerAdvice +public class GlobalExceptionHandler { + + @ExceptionHandler(EmployeeNotFoundException.class) + public ResponseEntity EmployeeNotFoundException(EmployeeNotFoundException ex) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(ex.getMessage()); + } + + @ExceptionHandler(PlaceNotFoundException.class) + public ResponseEntity PlaceNotFoundException(PlaceNotFoundException ex) { + return ResponseEntity.badRequest().body("Что-то пошло не так"); + } + + @ExceptionHandler(BookingConflictException.class) + public ResponseEntity BookingConflictException(BookingConflictException ex) { + return ResponseEntity.status(HttpStatus.CONFLICT).body(ex.getMessage()); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity Exception(Exception ex) { + return ResponseEntity.badRequest().body("Что-то пошло не так"); + } +} diff --git a/src/main/java/com/example/nto/Exception/PlaceNotFoundException.java b/src/main/java/com/example/nto/Exception/PlaceNotFoundException.java new file mode 100644 index 0000000..6b11cf6 --- /dev/null +++ b/src/main/java/com/example/nto/Exception/PlaceNotFoundException.java @@ -0,0 +1,7 @@ +package com.example.nto.Exception; + +public class PlaceNotFoundException extends RuntimeException { + public PlaceNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/nto/controller/BookingController.java b/src/main/java/com/example/nto/controller/BookingController.java index 9885f84..6e3923a 100644 --- a/src/main/java/com/example/nto/controller/BookingController.java +++ b/src/main/java/com/example/nto/controller/BookingController.java @@ -1,10 +1,59 @@ package com.example.nto.controller; +import com.example.nto.entity.Place; +import com.example.nto.service.BookingService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@RestController +@RequestMapping("/api/{code}") +@RequiredArgsConstructor public class BookingController { + private final BookingService bookingService; + + @GetMapping("/booking") + public ResponseEntity getAvailableBooking(@PathVariable String code) { + Map> places = bookingService.getAvailablePlaces(code); + + Map>> result = new TreeMap<>(); + for (Map.Entry> e : places.entrySet()) { + List> placeList = e.getValue().stream().map(p -> { + Map m = new HashMap<>(); + m.put("id", p.getId()); + m.put("place", p.getPlaceName()); + return m; + }).toList(); + result.put(e.getKey().toString(), placeList); + } + return ResponseEntity.ok(result); + } + + @PostMapping("/book") + public ResponseEntity createBooking(@PathVariable String code, @RequestBody Map request) { +// try { + String dateStr = (String) request.get("date"); + Long placeID = Long.valueOf(String.valueOf(request.get("placeID"))); + LocalDate date = LocalDate.parse(dateStr); + + bookingService.createBooking(code, date, placeID); + return ResponseEntity.status(201).build(); + // } +// catch (Exception ex) { +// return ResponseEntity.badRequest().body("Что-то пошло не так"); +// } + } + } diff --git a/src/main/java/com/example/nto/controller/EmployeeController.java b/src/main/java/com/example/nto/controller/EmployeeController.java index 47658f9..a61d7c8 100644 --- a/src/main/java/com/example/nto/controller/EmployeeController.java +++ b/src/main/java/com/example/nto/controller/EmployeeController.java @@ -1,10 +1,60 @@ package com.example.nto.controller; +import com.example.nto.entity.Booking; +import com.example.nto.entity.Employee; +import com.example.nto.entity.Place; +import com.example.nto.service.BookingService; +import com.example.nto.service.EmployeeService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ + +@RestController +@RequestMapping("/api/{code}") +@RequiredArgsConstructor public class EmployeeController { + private final EmployeeService employeeService; + + @GetMapping("/auth") + public ResponseEntity auth(@PathVariable String code) { + employeeService.findByCode(code); + return ResponseEntity.ok().build(); + } + + @GetMapping("/info") + public ResponseEntity getInfo(@PathVariable String code) { + Employee employee = employeeService.findByCode(code); + + // Формирование booking map (дата -> booking details) + Map response = new HashMap<>(); + response.put("name", employee.getName()); + response.put("photoUrl", employee.getPhotoUrl()); + + Map> bookingMap = new HashMap<>(); + if (employee.getBookingList() != null) { + for (Booking bk : employee.getBookingList()) { + Map bookingDetails = new HashMap<>(); + bookingDetails.put("id", bk.getId()); + bookingDetails.put("place", bk.getPlaceId()); // можно заменить на placeName, если нужно join + bookingMap.put(bk.getDate().toString(), bookingDetails); + } + } + response.put("booking", bookingMap); + + return ResponseEntity.ok(response); + } } diff --git a/src/main/java/com/example/nto/entity/Booking.java b/src/main/java/com/example/nto/entity/Booking.java index 21c1981..cb605e9 100644 --- a/src/main/java/com/example/nto/entity/Booking.java +++ b/src/main/java/com/example/nto/entity/Booking.java @@ -1,8 +1,6 @@ package com.example.nto.entity; -import jakarta.persistence.FetchType; -import jakarta.persistence.JoinColumn; -import jakarta.persistence.ManyToOne; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -21,15 +19,20 @@ import java.time.LocalDate; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity +@Table(name = "booking") public class Booking { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; - private long id; - + @Column(name = "date") private LocalDate date; - @ManyToOne(targetEntity = Place.class, fetch = FetchType.LAZY) - @JoinColumn(name = "place_id") - private Place place; + @Column(name = "place_id") + private Long placeId; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "employee_id") private Employee employee; -} +} \ No newline at end of file diff --git a/src/main/java/com/example/nto/entity/Employee.java b/src/main/java/com/example/nto/entity/Employee.java index a52102b..a1a0d87 100644 --- a/src/main/java/com/example/nto/entity/Employee.java +++ b/src/main/java/com/example/nto/entity/Employee.java @@ -19,14 +19,21 @@ import java.util.List; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity +@Table(name = "employee") public class Employee { - private long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Column(name = "name") private String name; + @Column(name = "code") private String code; + @Column(name = "photo_url") private String photoUrl; @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY) diff --git a/src/main/java/com/example/nto/entity/Place.java b/src/main/java/com/example/nto/entity/Place.java index 00c253b..b6c997d 100644 --- a/src/main/java/com/example/nto/entity/Place.java +++ b/src/main/java/com/example/nto/entity/Place.java @@ -1,8 +1,6 @@ package com.example.nto.entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; +import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -19,11 +17,13 @@ import lombok.NoArgsConstructor; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity +@Table(name = "place") public class Place { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private long id; + private Long id; - private String place; -} + @Column(name = "place_name") + private String placeName; +} \ No newline at end of file diff --git a/src/main/java/com/example/nto/repository/BookingRepository.java b/src/main/java/com/example/nto/repository/BookingRepository.java index 303bb54..2b2ee05 100644 --- a/src/main/java/com/example/nto/repository/BookingRepository.java +++ b/src/main/java/com/example/nto/repository/BookingRepository.java @@ -1,10 +1,24 @@ package com.example.nto.repository; +import com.example.nto.entity.Booking; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.time.LocalDate; +import java.util.List; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -public interface BookingRepository { -} +@Repository + +public interface BookingRepository extends JpaRepository { + List findByDateBetween(LocalDate startDate, LocalDate endDate); + + List findByDate(LocalDate date); + + boolean existsByDateAndPlaceId(LocalDate date, Long placeId); +} \ No newline at end of file diff --git a/src/main/java/com/example/nto/repository/EmployeeRepository.java b/src/main/java/com/example/nto/repository/EmployeeRepository.java index 210d29c..212c682 100644 --- a/src/main/java/com/example/nto/repository/EmployeeRepository.java +++ b/src/main/java/com/example/nto/repository/EmployeeRepository.java @@ -1,10 +1,18 @@ package com.example.nto.repository; +import com.example.nto.entity.Employee; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.Optional; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -public interface EmployeeRepository { -} +@Repository +public interface EmployeeRepository extends JpaRepository { + Optional findByCode(String code); +} \ No newline at end of file diff --git a/src/main/java/com/example/nto/repository/PlaceRepository.java b/src/main/java/com/example/nto/repository/PlaceRepository.java index d3bea1d..67e4b81 100644 --- a/src/main/java/com/example/nto/repository/PlaceRepository.java +++ b/src/main/java/com/example/nto/repository/PlaceRepository.java @@ -1,10 +1,15 @@ package com.example.nto.repository; +import com.example.nto.entity.Place; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ -public interface PlaceRepository { -} +@Repository +public interface PlaceRepository extends JpaRepository { + } \ No newline at end of file diff --git a/src/main/java/com/example/nto/service/BookingService.java b/src/main/java/com/example/nto/service/BookingService.java index 31ec148..81a15b1 100644 --- a/src/main/java/com/example/nto/service/BookingService.java +++ b/src/main/java/com/example/nto/service/BookingService.java @@ -1,5 +1,12 @@ package com.example.nto.service; +import com.example.nto.entity.Booking; +import com.example.nto.entity.Place; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= @@ -7,4 +14,6 @@ package com.example.nto.service; * НЕЛЬЗЯ: Изменять название класса и пакета */ public interface BookingService { + Map> getAvailablePlaces(String code); + Booking createBooking(String code, LocalDate date, Long placeId); } diff --git a/src/main/java/com/example/nto/service/EmployeeService.java b/src/main/java/com/example/nto/service/EmployeeService.java index cccd209..e07fffe 100644 --- a/src/main/java/com/example/nto/service/EmployeeService.java +++ b/src/main/java/com/example/nto/service/EmployeeService.java @@ -1,5 +1,10 @@ package com.example.nto.service; +import com.example.nto.entity.Employee; +import com.example.nto.repository.EmployeeRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= @@ -7,4 +12,5 @@ package com.example.nto.service; * НЕЛЬЗЯ: Изменять название класса и пакета */ public interface EmployeeService { -} + public Employee findByCode(String code); +} \ No newline at end of file diff --git a/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java b/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java index d24b244..34c03d6 100644 --- a/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java +++ b/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java @@ -1,6 +1,26 @@ package com.example.nto.service.impl; +import com.example.nto.Exception.BookingConflictException; +import com.example.nto.Exception.EmployeeNotFoundException; +import com.example.nto.Exception.PlaceNotFoundException; +import com.example.nto.entity.Booking; +import com.example.nto.entity.Employee; +import com.example.nto.entity.Place; +import com.example.nto.repository.BookingRepository; +import com.example.nto.repository.EmployeeRepository; +import com.example.nto.repository.PlaceRepository; import com.example.nto.service.BookingService; +import com.example.nto.service.EmployeeService; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +import java.time.LocalDate; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -8,5 +28,63 @@ import com.example.nto.service.BookingService; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@RequiredArgsConstructor +@Service public class BookingServiceImpl implements BookingService { + private final BookingRepository bookingRepository; + private final PlaceRepository placeRepository; + private final EmployeeService employeeService; + + // Максимальное количество дней вперед для брони из конфигурации (например 3) + private static final int DAYS_AHEAD = 3; + private final EmployeeRepository employeeRepository; + + public Map> getAvailablePlaces(String code) { + Employee employee = employeeService.findByCode(code); + LocalDate today = LocalDate.now(); + LocalDate endDate = today.plusDays(DAYS_AHEAD); + + List allBookings = bookingRepository.findByDateBetween(today, endDate); + + List allPlaces = placeRepository.findAll(); + Map> availablePlacesByDate = new HashMap<>(); + for (LocalDate date = today; !date.isAfter(endDate); date = date.plusDays(1)) { + LocalDate currentDate = date; + // Найти занятые места в этот день + Set bookedPlaceIds = allBookings.stream() + .filter(b -> b.getDate().equals(currentDate)) + .map(Booking::getPlaceId) + .collect(Collectors.toSet()); + + // Оставшиеся места свободны + List freePlaces = allPlaces.stream() + .filter(p -> !bookedPlaceIds.contains(p.getId())) + .collect(Collectors.toList()); + + availablePlacesByDate.put(currentDate, freePlaces); + } + + return availablePlacesByDate; +} + + @Transactional + public Booking createBooking(String code, LocalDate date, Long placeId) { + + if (employeeRepository.findByCode(code).isEmpty()) throw new EmployeeNotFoundException("Кода не существует"); + if (!placeRepository.existsById(placeId)) { + throw new PlaceNotFoundException("Место не существует"); + } + + if (bookingRepository.existsByDateAndPlaceId(date, placeId)) { + throw new BookingConflictException("Уже забронировано"); + } + + Employee employee = employeeService.findByCode(code); + Booking booking = new Booking(); + booking.setDate(date); + booking.setPlaceId(placeId); + booking.setEmployee(employee); + + return bookingRepository.save(booking); + } } diff --git a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java index f8125e5..5404910 100644 --- a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java +++ b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java @@ -1,6 +1,11 @@ package com.example.nto.service.impl; +import com.example.nto.Exception.EmployeeNotFoundException; +import com.example.nto.entity.Employee; +import com.example.nto.repository.EmployeeRepository; import com.example.nto.service.EmployeeService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -8,5 +13,13 @@ import com.example.nto.service.EmployeeService; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@Service +@RequiredArgsConstructor public class EmployeeServiceImpl implements EmployeeService { + private final EmployeeRepository employeeRepository; + + public Employee findByCode(String code) { + return employeeRepository.findByCode(code) + .orElseThrow(() -> new EmployeeNotFoundException("Кода не существует")); + } }