diff --git a/src/main/java/com/example/nto/App.java b/src/main/java/com/example/nto/App.java index e453f89..f854da5 100644 --- a/src/main/java/com/example/nto/App.java +++ b/src/main/java/com/example/nto/App.java @@ -1,12 +1,19 @@ package com.example.nto; +import org.springframework.boot.SpringApplication; + +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/controller/BookingController.java b/src/main/java/com/example/nto/controller/BookingController.java index 9885f84..6ea0851 100644 --- a/src/main/java/com/example/nto/controller/BookingController.java +++ b/src/main/java/com/example/nto/controller/BookingController.java @@ -1,10 +1,50 @@ package com.example.nto.controller; +import com.example.nto.dto.BookRequest; +import com.example.nto.dto.PlaceInfo; +import com.example.nto.service.BookingService; +import com.example.nto.service.EmployeeService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor public class BookingController { + + private final BookingService bookingService; + private final EmployeeService employeeService; + + @GetMapping("/{code}/booking") + public ResponseEntity getAvailablePlaces(@PathVariable String code) { + if (employeeService.getEmployeeByCode(code).isEmpty()) { + return new ResponseEntity<>("кода не существует", HttpStatus.UNAUTHORIZED); + } + try { + Map> availablePlaces = bookingService.getAvailablePlaces(); + return new ResponseEntity<>(availablePlaces, HttpStatus.OK); + } catch (Exception e) { + return new ResponseEntity<>("что-то пошло не так", HttpStatus.BAD_REQUEST); + } + } + + @PostMapping("/{code}/book") + public ResponseEntity bookPlace(@PathVariable String code, @RequestBody BookRequest bookRequest) { + if (employeeService.getEmployeeByCode(code).isEmpty()) { + return new ResponseEntity<>("кода не существует", HttpStatus.UNAUTHORIZED); + } + return bookingService.createBooking(code, bookRequest); + } } diff --git a/src/main/java/com/example/nto/controller/EmployeeController.java b/src/main/java/com/example/nto/controller/EmployeeController.java index 47658f9..5b17ef8 100644 --- a/src/main/java/com/example/nto/controller/EmployeeController.java +++ b/src/main/java/com/example/nto/controller/EmployeeController.java @@ -1,10 +1,55 @@ package com.example.nto.controller; +import com.example.nto.dto.UserInfoResponse; +import com.example.nto.service.BookingService; +import com.example.nto.service.EmployeeService; +import lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.NoSuchElementException; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@RestController +@RequestMapping("/api") +@RequiredArgsConstructor public class EmployeeController { + + private final EmployeeService employeeService; + private final BookingService bookingService; + + @GetMapping("/{code}/auth") + public ResponseEntity auth(@PathVariable String code) { + try { + if (employeeService.getEmployeeByCode(code).isPresent()) { + return new ResponseEntity<>("данный код существует - можно пользоваться приложением", HttpStatus.OK); + } else { + return new ResponseEntity<>("кода не существует", HttpStatus.UNAUTHORIZED); + } + } catch (Exception e) { + return new ResponseEntity<>("что-то пошло не так", HttpStatus.BAD_REQUEST); + } + } + + @GetMapping("/{code}/info") + public ResponseEntity getInfo(@PathVariable String code) { + if (employeeService.getEmployeeByCode(code).isEmpty()) { + return new ResponseEntity<>("кода не существует", HttpStatus.UNAUTHORIZED); + } + try { + UserInfoResponse userInfo = bookingService.getUserInfo(code); + return new ResponseEntity<>(userInfo, HttpStatus.OK); + } catch (NoSuchElementException e) { + return new ResponseEntity<>("что-то пошло не так", HttpStatus.BAD_REQUEST); + } + } } diff --git a/src/main/java/com/example/nto/dto/BookRequest.java b/src/main/java/com/example/nto/dto/BookRequest.java new file mode 100644 index 0000000..41587cf --- /dev/null +++ b/src/main/java/com/example/nto/dto/BookRequest.java @@ -0,0 +1,15 @@ +package com.example.nto.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class BookRequest { + private LocalDate date; + private Long placeId; +} diff --git a/src/main/java/com/example/nto/dto/PlaceInfo.java b/src/main/java/com/example/nto/dto/PlaceInfo.java new file mode 100644 index 0000000..98498b9 --- /dev/null +++ b/src/main/java/com/example/nto/dto/PlaceInfo.java @@ -0,0 +1,13 @@ +package com.example.nto.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PlaceInfo { + private long id; + private String place; +} diff --git a/src/main/java/com/example/nto/dto/UserInfoResponse.java b/src/main/java/com/example/nto/dto/UserInfoResponse.java new file mode 100644 index 0000000..d422cbf --- /dev/null +++ b/src/main/java/com/example/nto/dto/UserInfoResponse.java @@ -0,0 +1,18 @@ +package com.example.nto.dto; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; +import java.util.Map; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserInfoResponse { + private String name; + private String photoUrl; + private Map booking; +} diff --git a/src/main/java/com/example/nto/entity/Booking.java b/src/main/java/com/example/nto/entity/Booking.java index 21c1981..67e2a25 100644 --- a/src/main/java/com/example/nto/entity/Booking.java +++ b/src/main/java/com/example/nto/entity/Booking.java @@ -1,4 +1,9 @@ package com.example.nto.entity; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import jakarta.persistence.Id; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; import jakarta.persistence.FetchType; import jakarta.persistence.JoinColumn; @@ -21,8 +26,12 @@ import java.time.LocalDate; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity(name = "booking") +@Table(name = "booking") public class Booking { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; private LocalDate date; @@ -31,5 +40,7 @@ public class Booking { @JoinColumn(name = "place_id") private Place place; + @ManyToOne(targetEntity = Employee.class, fetch = FetchType.LAZY) + @JoinColumn(name = "employee_id") private Employee employee; } diff --git a/src/main/java/com/example/nto/entity/Employee.java b/src/main/java/com/example/nto/entity/Employee.java index a52102b..eefa4b0 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(name = "employee") +@Table(name = "employee") public class Employee { + @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..00747bb 100644 --- a/src/main/java/com/example/nto/entity/Place.java +++ b/src/main/java/com/example/nto/entity/Place.java @@ -3,6 +3,9 @@ package com.example.nto.entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; +import jakarta.persistence.Column; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; @@ -19,11 +22,14 @@ import lombok.NoArgsConstructor; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity(name = "place") +@Table(name = "place") public class Place { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; + @Column(name = "place_name") private String place; } diff --git a/src/main/java/com/example/nto/repository/BookingRepository.java b/src/main/java/com/example/nto/repository/BookingRepository.java index 303bb54..523f0f4 100644 --- a/src/main/java/com/example/nto/repository/BookingRepository.java +++ b/src/main/java/com/example/nto/repository/BookingRepository.java @@ -1,10 +1,22 @@ 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 findAllByDateIn(List dates); + + boolean existsByDateAndPlaceId(LocalDate date, Long placeId); } diff --git a/src/main/java/com/example/nto/repository/EmployeeRepository.java b/src/main/java/com/example/nto/repository/EmployeeRepository.java index 210d29c..f05aa8d 100644 --- a/src/main/java/com/example/nto/repository/EmployeeRepository.java +++ b/src/main/java/com/example/nto/repository/EmployeeRepository.java @@ -1,10 +1,19 @@ 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); } diff --git a/src/main/java/com/example/nto/repository/PlaceRepository.java b/src/main/java/com/example/nto/repository/PlaceRepository.java index d3bea1d..425dacb 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 { } diff --git a/src/main/java/com/example/nto/service/BookingService.java b/src/main/java/com/example/nto/service/BookingService.java index 31ec148..7e2f3d0 100644 --- a/src/main/java/com/example/nto/service/BookingService.java +++ b/src/main/java/com/example/nto/service/BookingService.java @@ -1,5 +1,14 @@ package com.example.nto.service; +import com.example.nto.dto.BookRequest; +import com.example.nto.dto.PlaceInfo; +import com.example.nto.dto.UserInfoResponse; +import org.springframework.http.ResponseEntity; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= @@ -7,4 +16,9 @@ package com.example.nto.service; * НЕЛЬЗЯ: Изменять название класса и пакета */ public interface BookingService { + Map> getAvailablePlaces(); + + ResponseEntity createBooking(String code, BookRequest bookRequest); + + UserInfoResponse getUserInfo(String code); } diff --git a/src/main/java/com/example/nto/service/EmployeeService.java b/src/main/java/com/example/nto/service/EmployeeService.java index cccd209..dd94b8f 100644 --- a/src/main/java/com/example/nto/service/EmployeeService.java +++ b/src/main/java/com/example/nto/service/EmployeeService.java @@ -1,5 +1,9 @@ package com.example.nto.service; +import com.example.nto.entity.Employee; + +import java.util.Optional; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= @@ -7,4 +11,6 @@ package com.example.nto.service; * НЕЛЬЗЯ: Изменять название класса и пакета */ public interface EmployeeService { + + Optional getEmployeeByCode(String code); } 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..7e9e724 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,29 @@ package com.example.nto.service.impl; +import com.example.nto.dto.BookRequest; +import com.example.nto.dto.PlaceInfo; +import com.example.nto.dto.UserInfoResponse; +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 lombok.RequiredArgsConstructor; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.TreeMap; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -8,5 +31,79 @@ import com.example.nto.service.BookingService; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@Service +@RequiredArgsConstructor public class BookingServiceImpl implements BookingService { + + private final BookingRepository bookingRepository; + private final PlaceRepository placeRepository; + private final EmployeeRepository employeeRepository; + + @Override + @Transactional(readOnly = true) + public Map> getAvailablePlaces() { + List dates = Stream.iterate(LocalDate.now(), date -> date.plusDays(1)) + .limit(4) + .toList(); + + List bookings = bookingRepository.findAllByDateIn(dates); + List places = placeRepository.findAll(); + + return dates.stream() + .collect(Collectors.toMap( + Function.identity(), + date -> { + List bookedPlaceIds = bookings.stream() + .filter(booking -> booking.getDate().equals(date)) + .map(booking -> booking.getPlace().getId()) + .toList(); + return places.stream() + .filter(place -> !bookedPlaceIds.contains(place.getId())) + .map(place -> new PlaceInfo(place.getId(), place.getPlace())) + .toList(); + }, + (existing, replacement) -> existing, + TreeMap::new)); + } + + @Override + @Transactional + public ResponseEntity createBooking(String code, BookRequest bookRequest) { + Optional employeeOptional = employeeRepository.findByCode(code); + if (employeeOptional.isEmpty()) { + return new ResponseEntity<>("кода не существует", HttpStatus.UNAUTHORIZED); + } + + Optional placeOptional = placeRepository.findById(bookRequest.getPlaceId()); + // System.out.println("asdasd"+placeOptional.get()); + if (placeOptional.isEmpty()) { + return new ResponseEntity<>("что-то пошло не так", HttpStatus.BAD_REQUEST); + } + + if (bookingRepository.existsByDateAndPlaceId(bookRequest.getDate(), bookRequest.getPlaceId())) { + return new ResponseEntity<>("уже забронировано", HttpStatus.CONFLICT); + } + + + Booking booking = Booking.builder() + .date(bookRequest.getDate()) + .place(placeOptional.get()) + .employee(employeeOptional.get()) + .build(); + bookingRepository.save(booking); + + return new ResponseEntity<>("бронирование успешно создано", HttpStatus.CREATED); + } + + @Override + @Transactional(readOnly = true) + public UserInfoResponse getUserInfo(String code) { + Employee employee = employeeRepository.findByCode(code).orElseThrow(); + Map bookings = employee.getBookingList().stream() + .collect(Collectors.toMap( + Booking::getDate, + booking -> new PlaceInfo(booking.getPlace().getId(), booking.getPlace().getPlace()))); + + return new UserInfoResponse(employee.getName(), employee.getPhotoUrl(), bookings); + } } 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..dfc122a 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,12 @@ package com.example.nto.service.impl; +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; + +import java.util.Optional; /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -8,5 +14,14 @@ import com.example.nto.service.EmployeeService; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@Service +@RequiredArgsConstructor public class EmployeeServiceImpl implements EmployeeService { + + private final EmployeeRepository employeeRepository; + + @Override + public Optional getEmployeeByCode(String code) { + return employeeRepository.findByCode(code); + } }