diff --git a/src/main/java/com/example/nto/App.java b/src/main/java/com/example/nto/App.java index e453f89..ad42870 100644 --- a/src/main/java/com/example/nto/App.java +++ b/src/main/java/com/example/nto/App.java @@ -1,4 +1,8 @@ package com.example.nto; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -6,7 +10,9 @@ package com.example.nto; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@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..9b4dd45 100644 --- a/src/main/java/com/example/nto/controller/BookingController.java +++ b/src/main/java/com/example/nto/controller/BookingController.java @@ -1,10 +1,77 @@ package com.example.nto.controller; +import com.example.nto.excepation.EmployeeNotFoundException; +import com.example.nto.repository.BookingRepository; +import com.example.nto.repository.PlaceRepository; +import com.example.nto.service.BookingService; +import com.example.nto.service.EmployeeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.util.Map; + /** * TODO: ДОРАБОТАТЬ в рамках задания * ================================= * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@RestController +@RequestMapping("/api") public class BookingController { + @Autowired + private BookingService bookingService; + @Autowired + private PlaceRepository placeRepository; + @Autowired + private BookingRepository bookingRepository; + @Autowired + private EmployeeService employeeService; + @GetMapping("/{code}/booking") + public ResponseEntity getAvailableBookings(@PathVariable String code) { + try { + if (code == null || code.trim().isEmpty()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Employee code cannot be null or empty"); + } + Map response = bookingService.findAvailableBookings(code); + return ResponseEntity.ok(response); + } catch (IllegalArgumentException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); + } catch (EmployeeNotFoundException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage()); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Unexpected error"); + } + } + @PostMapping("/{code}/book") + public ResponseEntity createBooking( + @PathVariable String code, + @RequestBody Map body + ) { + try { + Long placeId = body.get("placeId") != null ? Long.valueOf(body.get("placeId").toString()) : null; + String date = body.get("date") != null ? body.get("date").toString() : null; + if (placeId == null || date == null || date.isEmpty()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Place ID and date must be provided"); + } + String message = bookingService.createBooking(code, placeId, date); + return ResponseEntity.ok(message); + } catch (IllegalArgumentException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); + } catch (EmployeeNotFoundException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage()); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Unexpected error"); + } + } + @DeleteMapping("/{id}") + public ResponseEntity deleteBooking(@PathVariable Long id) { + bookingService.deleteBooking(id); + return ResponseEntity.noContent().build(); + } } + + + + diff --git a/src/main/java/com/example/nto/controller/EmployeeController.java b/src/main/java/com/example/nto/controller/EmployeeController.java index 47658f9..a94aacb 100644 --- a/src/main/java/com/example/nto/controller/EmployeeController.java +++ b/src/main/java/com/example/nto/controller/EmployeeController.java @@ -1,4 +1,18 @@ package com.example.nto.controller; +import com.example.nto.entity.Booking; +import com.example.nto.entity.Employee; +import com.example.nto.excepation.EmployeeNotFoundException; +import com.example.nto.repository.BookingRepository; +import com.example.nto.service.EmployeeService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -6,5 +20,51 @@ package com.example.nto.controller; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@RestController +@RequestMapping("/api") public class EmployeeController { + @Autowired + private EmployeeService employeeService; + @Autowired + private BookingRepository bookingRepository; + + @GetMapping("/{code}/auth") + public ResponseEntity checkAuth( + @PathVariable String code) { + if (code == null) { + throw new IllegalArgumentException("Employee code is required"); + } + try { + employeeService.getEmployeeByCode(code); + return ResponseEntity.ok("Authorized Employee"); + } catch (IllegalArgumentException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + } catch (EmployeeNotFoundException e) { + return ResponseEntity.status(HttpStatus.NOT_FOUND).build(); + } + } + @GetMapping("/{code}/info") + public ResponseEntity getEmployeeInfo(@PathVariable String code) { + try { + if (code == null || code.trim().isEmpty()) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST) + .body("Employee code cannot be null or empty"); + } + Employee employee = employeeService.getEmployeeByCode(code); + List bookings = bookingRepository.findByEmployeeId(employee.getId()); + Map>> bookingMap = bookings.stream().collect(Collectors.groupingBy(b -> b.getDate().toString(),LinkedHashMap::new,Collectors.mapping(b -> Map.of("id", b.getId(),"place", b.getPlace().getPlace()), Collectors.toList()))); + Map response = new LinkedHashMap<>(); + response.put("name", employee.getName()); + response.put("photoUrl", employee.getPhotoUrl()); + response.put("booking", bookingMap); + return ResponseEntity.ok(response); + } catch (IllegalArgumentException e) { + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); + } catch (EmployeeNotFoundException e) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(e.getMessage()); + } catch (Exception e) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body("Unexpected error"); + } + } } diff --git a/src/main/java/com/example/nto/entity/Booking.java b/src/main/java/com/example/nto/entity/Booking.java index 21c1981..8a6f0cd 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,44 @@ import java.time.LocalDate; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity +@Table(name="booking") public class Booking { - + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; - private LocalDate date; - @ManyToOne(targetEntity = Place.class, fetch = FetchType.LAZY) @JoinColumn(name = "place_id") private Place place; - + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "employee_id") private Employee employee; + + + public Place getPlace() { + return place; + } + public LocalDate getDate() { + return date; + } + + public Object getId() { + return id; + } + + public Employee getEmployee() { + return employee; + } + + public void setDate(LocalDate date) { + this.date = date; + } + + public void setPlace(Place place) { + this.place = place; + } + public void setEmployee(Employee employee) { + this.employee = (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..19e13dc 100644 --- a/src/main/java/com/example/nto/entity/Employee.java +++ b/src/main/java/com/example/nto/entity/Employee.java @@ -1,11 +1,14 @@ package com.example.nto.entity; +import com.fasterxml.jackson.annotation.JsonIgnore; import jakarta.persistence.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; @@ -19,16 +22,23 @@ import java.util.List; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity +@Table(name="employee") public class Employee { - + @Id private long id; + private String name; private String code; private String photoUrl; + @OneToMany(mappedBy = "employee", fetch = FetchType.LAZY, cascade = CascadeType.ALL) + private List bookings = new ArrayList<>(); - @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY) - private List bookingList; + public long getId() { return id; } + public String getName() { return name; } + public String getCode() { return code; } + public String getPhotoUrl() { return photoUrl; } } diff --git a/src/main/java/com/example/nto/entity/Place.java b/src/main/java/com/example/nto/entity/Place.java index 00c253b..32947c7 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,26 @@ import lombok.NoArgsConstructor; @Builder @NoArgsConstructor @AllArgsConstructor +@Entity +@Table(name="place") public class Place { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; - + @Column(name = "place_name") private String place; + + public Place(int id, String place) { + } + + + public Object getPlace() { + return place; + } + + public Long getId() { + return id; + } } + + + diff --git a/src/main/java/com/example/nto/excepation/EmployeeNotFoundException.java b/src/main/java/com/example/nto/excepation/EmployeeNotFoundException.java new file mode 100644 index 0000000..7de98f7 --- /dev/null +++ b/src/main/java/com/example/nto/excepation/EmployeeNotFoundException.java @@ -0,0 +1,7 @@ +package com.example.nto.excepation; + +public class EmployeeNotFoundException extends RuntimeException{ + public EmployeeNotFoundException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/nto/excepation/IllegalArgumentException.java b/src/main/java/com/example/nto/excepation/IllegalArgumentException.java new file mode 100644 index 0000000..00cc715 --- /dev/null +++ b/src/main/java/com/example/nto/excepation/IllegalArgumentException.java @@ -0,0 +1,7 @@ +package com.example.nto.excepation; + +public class IllegalArgumentException extends RuntimeException { + public IllegalArgumentException(String message) { + super(message); + } +} diff --git a/src/main/java/com/example/nto/repository/BookingRepository.java b/src/main/java/com/example/nto/repository/BookingRepository.java index 303bb54..7f13184 100644 --- a/src/main/java/com/example/nto/repository/BookingRepository.java +++ b/src/main/java/com/example/nto/repository/BookingRepository.java @@ -1,10 +1,20 @@ 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 start, LocalDate end); + List findByEmployeeId(long id); } 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..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..cdaf573 100644 --- a/src/main/java/com/example/nto/service/BookingService.java +++ b/src/main/java/com/example/nto/service/BookingService.java @@ -1,10 +1,11 @@ package com.example.nto.service; -/** - * TODO: ДОРАБОТАТЬ в рамках задания - * ================================= - * МОЖНО: Добавлять методы, аннотации, зависимости - * НЕЛЬЗЯ: Изменять название класса и пакета - */ +import org.springframework.stereotype.Service; +import java.util.Map; + +@Service public interface BookingService { + Map findAvailableBookings(String employeeCode); + String createBooking(String code, Long placeId, String date); + void deleteBooking(long id); } diff --git a/src/main/java/com/example/nto/service/EmployeeService.java b/src/main/java/com/example/nto/service/EmployeeService.java index cccd209..c741635 100644 --- a/src/main/java/com/example/nto/service/EmployeeService.java +++ b/src/main/java/com/example/nto/service/EmployeeService.java @@ -1,4 +1,6 @@ package com.example.nto.service; +import com.example.nto.entity.Employee; +import org.springframework.stereotype.Service; /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -6,5 +8,7 @@ package com.example.nto.service; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@Service public interface EmployeeService { + Employee getEmployeeByCode(String code); } diff --git a/src/main/java/com/example/nto/service/PlaceServise.java b/src/main/java/com/example/nto/service/PlaceServise.java new file mode 100644 index 0000000..53771b0 --- /dev/null +++ b/src/main/java/com/example/nto/service/PlaceServise.java @@ -0,0 +1,22 @@ +package com.example.nto.service; +import com.example.nto.entity.Place; +import com.example.nto.repository.PlaceRepository; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +public class PlaceServise { + @Autowired + private PlaceRepository placeRepository; + @PostConstruct + public void Places() { + if(placeRepository.count() == 0) { + placeRepository.save(new Place(1,"K-19")); + placeRepository.save(new Place(2,"M-16")); + placeRepository.save(new Place(3,"T-1")); + } + } + +} + 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..cb07759 100644 --- a/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java +++ b/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java @@ -1,12 +1,102 @@ package com.example.nto.service.impl; +import com.example.nto.entity.Booking; +import com.example.nto.entity.Employee; +import com.example.nto.entity.Place; +import com.example.nto.excepation.EmployeeNotFoundException; +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 org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; -/** - * TODO: ДОРАБОТАТЬ в рамках задания - * ================================= - * МОЖНО: Добавлять методы, аннотации, зависимости - * НЕЛЬЗЯ: Изменять название класса и пакета - */ +import java.time.LocalDate; +import java.util.*; + +@Service public class BookingServiceImpl implements BookingService { + @Autowired + private BookingRepository bookingRepository; + @Autowired + private PlaceRepository placeRepository; + @Autowired + private EmployeeService employeeService; + @Autowired + private EmployeeRepository employeeRepository; + @Override + public Map findAvailableBookings(String employeeCode) { + if (employeeCode == null || employeeCode.isEmpty()) { + throw new IllegalArgumentException("Employee code cannot be null or empty"); + } + Employee employee = employeeService.getEmployeeByCode(employeeCode); + if (employee == null) { + throw new EmployeeNotFoundException("Employee not found with code: " + employeeCode); + } + LocalDate today = LocalDate.now(); + LocalDate endDate = today.plusDays(3); + List bookings = bookingRepository.findByDateBetween(today, endDate); + List places = placeRepository.findAll(); + Map>> result = new LinkedHashMap<>(); + for (int i = 0; i <= 3; i++) { + LocalDate date = today.plusDays(i); + List> freePlaces = new ArrayList<>(); + for (Place place : places) { + boolean isBooked = bookings.stream().anyMatch(b -> b.getDate().isEqual(date) && b.getPlace().getId() == place.getId()); + if (!isBooked) { + Map placeInfo = new LinkedHashMap<>(); + placeInfo.put("id", place.getId()); + placeInfo.put("place", place.getPlace()); + freePlaces.add(placeInfo); + } + } + result.put(date.toString(), freePlaces); + } + return Collections.unmodifiableMap(result); + } + public String createBooking(String code, Long placeId, String date) { + + if (code == null || code.isBlank()) { + throw new IllegalArgumentException("Employee code is empty"); + } + if (placeId == null || date == null || date.isBlank()) { + throw new IllegalArgumentException("Place ID and date must be provided"); + } + Employee employee = employeeRepository.findByCode(code).orElseThrow(() -> new EmployeeNotFoundException("Employee not found")); + Place place = placeRepository.findById(placeId).orElseThrow(() -> new IllegalArgumentException("Place not found")); + LocalDate bookingDate; + try { + bookingDate = LocalDate.parse(date); + } catch (Exception e) { + throw new IllegalArgumentException("Invalid date format. Use yyyy-MM-dd"); + } + boolean exists = bookingRepository.findByDateBetween(bookingDate, bookingDate).stream().anyMatch( + b -> b.getPlace() + .getId() == placeId); + if (exists) { + throw new IllegalArgumentException("Place already booked for this date"); + } + Booking booking = new Booking(); + booking.setEmployee((Employee) employee); + booking.setPlace(place); + booking.setDate(bookingDate); + bookingRepository.save(booking); + Map result = new LinkedHashMap<>(); + result.put("id", booking.getId()); + result.put("date", booking.getDate()); + result.put("placeId", place.getId()); + result.put("employeeId", employee.getId()); + return "the booking was created successfully"; + } + public void deleteBooking(long id) { + if (!bookingRepository.existsById(id)) { + throw new IllegalArgumentException("Booking not found with id: " + id); + } + bookingRepository.deleteById(id); + } } + + + + 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..00a30f9 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.excepation.EmployeeNotFoundException; +import com.example.nto.repository.EmployeeRepository; import com.example.nto.service.EmployeeService; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + /** * TODO: ДОРАБОТАТЬ в рамках задания @@ -8,5 +14,16 @@ import com.example.nto.service.EmployeeService; * МОЖНО: Добавлять методы, аннотации, зависимости * НЕЛЬЗЯ: Изменять название класса и пакета */ +@Service +@RequiredArgsConstructor public class EmployeeServiceImpl implements EmployeeService { -} + @Autowired + private EmployeeRepository employeeRepository; + @Override + public Employee getEmployeeByCode(String code) { + if (code == null || code.isEmpty()) { + throw new IllegalArgumentException("Employee code is required"); + } + return employeeRepository.findByCode(code).orElseThrow(() -> new EmployeeNotFoundException("Employee not found")); + } +} \ No newline at end of file