-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[Feat] 예약 현황 조회 / 예약 하기 기능 구현
- Loading branch information
Showing
22 changed files
with
720 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
21 changes: 21 additions & 0 deletions
21
nowait-api/src/main/java/com/nowait/booking/application/BookingEventPublisher.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.nowait.booking.application; | ||
|
||
import com.nowait.booking.domain.model.Booking; | ||
import com.nowait.common.event.BookedEvent; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.context.ApplicationEventPublisher; | ||
import org.springframework.scheduling.annotation.Async; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Component | ||
@RequiredArgsConstructor | ||
public class BookingEventPublisher { | ||
|
||
private final ApplicationEventPublisher eventPublisher; | ||
|
||
@Async | ||
public void publishBookedEvent(Booking booking, Long placeId) { | ||
eventPublisher.publishEvent( | ||
new BookedEvent(booking.getId(), placeId, booking.getUserId())); | ||
} | ||
} |
80 changes: 80 additions & 0 deletions
80
nowait-api/src/main/java/com/nowait/booking/application/BookingService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
package com.nowait.booking.application; | ||
|
||
import com.nowait.booking.domain.model.Booking; | ||
import com.nowait.booking.domain.model.BookingSlot; | ||
import com.nowait.booking.domain.repository.BookingRepository; | ||
import com.nowait.booking.domain.repository.BookingSlotRepository; | ||
import com.nowait.booking.dto.TimeSlotDto; | ||
import com.nowait.booking.dto.response.BookingRes; | ||
import com.nowait.booking.dto.response.DailyBookingStatusRes; | ||
import com.nowait.place.domain.repository.PlaceRepository; | ||
import com.nowait.user.domain.repository.UserRepository; | ||
import jakarta.persistence.EntityNotFoundException; | ||
import java.time.LocalDate; | ||
import java.time.LocalTime; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
public class BookingService { | ||
|
||
private final BookingSlotRepository bookingSlotRepository; | ||
private final BookingRepository bookingRepository; | ||
private final UserRepository userRepository; | ||
private final PlaceRepository placeRepository; | ||
private final BookingEventPublisher bookingEventPublisher; | ||
|
||
public DailyBookingStatusRes getDailyBookingStatus(Long placeId, LocalDate date) { | ||
List<BookingSlot> bookingSlots = bookingSlotRepository.findAllByPlaceIdAndDate( | ||
placeId, date); | ||
|
||
List<TimeSlotDto> timeSlots = bookingSlots.stream() | ||
.collect(Collectors.groupingBy(BookingSlot::getTime)) | ||
.entrySet().stream() | ||
.map(entry -> new TimeSlotDto(entry.getKey(), isAvailable(entry.getValue()))) | ||
.toList(); | ||
|
||
return new DailyBookingStatusRes(placeId, date, timeSlots); | ||
} | ||
|
||
@Transactional | ||
public BookingRes book(Long loginId, Long placeId, LocalDate date, LocalTime time, | ||
Integer partySize) { | ||
validateUserExist(loginId, "존재하지 않는 사용자의 요청입니다."); | ||
validatePlaceExist(placeId, "존재하지 않는 식당입니다."); | ||
|
||
BookingSlot slot = findAvailableSlot(placeId, date, time); | ||
Booking booking = bookingRepository.save(Booking.of(loginId, partySize, slot)); | ||
|
||
bookingEventPublisher.publishBookedEvent(booking, placeId); | ||
|
||
return BookingRes.of(booking, slot); | ||
} | ||
|
||
private boolean isAvailable(List<BookingSlot> slots) { | ||
// 모든 슬롯이 예약된 경우에만 false 반환 | ||
return slots.stream().anyMatch(slot -> !slot.isBooked()); | ||
} | ||
|
||
private void validateUserExist(Long userId, String errorMessage) { | ||
if (!userRepository.existsById(userId)) { | ||
throw new EntityNotFoundException(errorMessage); | ||
} | ||
} | ||
|
||
private void validatePlaceExist(Long placeId, String errorMessage) { | ||
if (!placeRepository.existsById(placeId)) { | ||
throw new EntityNotFoundException(errorMessage); | ||
} | ||
} | ||
|
||
private BookingSlot findAvailableSlot(Long placeId, LocalDate date, LocalTime time) { | ||
return bookingSlotRepository.findFirstByPlaceIdAndDateAndTimeAndIsBookedFalse(placeId, date, | ||
time).orElseThrow(() -> new IllegalArgumentException("예약 가능한 테이블이 없습니다.")); | ||
} | ||
} |
51 changes: 51 additions & 0 deletions
51
nowait-api/src/main/java/com/nowait/booking/domain/model/Booking.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package com.nowait.booking.domain.model; | ||
|
||
import com.nowait.common.domain.model.BaseTimeEntity; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.EnumType; | ||
import jakarta.persistence.Enumerated; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.Table; | ||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Table(name = "booking") | ||
@Getter | ||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class Booking extends BaseTimeEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "id") | ||
private Long id; | ||
|
||
@Column(name = "booking_slot_id", nullable = false, unique = true) | ||
private Long bookingSlotId; | ||
|
||
@Column(name = "user_id", nullable = false) | ||
private Long userId; | ||
|
||
@Enumerated(value = EnumType.STRING) | ||
@Column(name = "status", nullable = false, columnDefinition = "varchar(20)") | ||
private BookingStatus status; | ||
|
||
@Column(name = "party_size") | ||
private Integer partySize; | ||
|
||
public static Booking of(Long userId, Integer partySize, BookingSlot slot) { | ||
return new Booking( | ||
null, | ||
slot.getId(), | ||
userId, | ||
slot.book(), | ||
partySize | ||
); | ||
} | ||
} |
63 changes: 63 additions & 0 deletions
63
nowait-api/src/main/java/com/nowait/booking/domain/model/BookingSlot.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
package com.nowait.booking.domain.model; | ||
|
||
import com.nowait.common.domain.model.BaseTimeEntity; | ||
import jakarta.persistence.Column; | ||
import jakarta.persistence.Entity; | ||
import jakarta.persistence.GeneratedValue; | ||
import jakarta.persistence.GenerationType; | ||
import jakarta.persistence.Id; | ||
import jakarta.persistence.Table; | ||
import java.time.LocalDate; | ||
import java.time.LocalTime; | ||
import lombok.AccessLevel; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
|
||
@Entity | ||
@Table(name = "booking_slot") | ||
@Getter | ||
@AllArgsConstructor(access = AccessLevel.PRIVATE) | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
public class BookingSlot extends BaseTimeEntity { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
@Column(name = "id") | ||
private Long id; | ||
|
||
@Column(name = "place_id", nullable = false) | ||
private Long placeId; | ||
|
||
@Column(name = "table_id", nullable = false) | ||
private Long tableId; | ||
|
||
@Column(name = "date", nullable = false) | ||
private LocalDate date; | ||
|
||
@Column(name = "time", nullable = false) | ||
private LocalTime time; | ||
|
||
@Column(name = "is_booked") | ||
private boolean isBooked; | ||
|
||
@Column(name = "deposit_required") | ||
private boolean depositRequired; | ||
|
||
@Column(name = "confirm_required") | ||
private boolean confirmRequired; | ||
|
||
@Column(name = "deposit_policy_id") | ||
private Long deposit_policy_id; | ||
|
||
public BookingStatus book() { | ||
if (isBooked) { | ||
throw new IllegalArgumentException("이미 예약된 테이블입니다."); | ||
} | ||
|
||
isBooked = true; | ||
|
||
return isDepositRequired() ? BookingStatus.PENDING_PAYMENT | ||
: isConfirmRequired() ? BookingStatus.PENDING_CONFIRM : BookingStatus.CONFIRMED; | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
nowait-api/src/main/java/com/nowait/booking/domain/model/BookingStatus.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.nowait.booking.domain.model; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum BookingStatus { | ||
CONFIRMED("확정됨"), | ||
PENDING_CONFIRM("확정 대기 중"), | ||
PENDING_PAYMENT("결재 대기 중"), | ||
CANCELLED("취소됨"); | ||
|
||
private final String description; | ||
} |
8 changes: 8 additions & 0 deletions
8
nowait-api/src/main/java/com/nowait/booking/domain/repository/BookingRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package com.nowait.booking.domain.repository; | ||
|
||
import com.nowait.booking.domain.model.Booking; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface BookingRepository extends JpaRepository<Booking, Long> { | ||
|
||
} |
16 changes: 16 additions & 0 deletions
16
nowait-api/src/main/java/com/nowait/booking/domain/repository/BookingSlotRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package com.nowait.booking.domain.repository; | ||
|
||
import com.nowait.booking.domain.model.BookingSlot; | ||
import java.time.LocalDate; | ||
import java.time.LocalTime; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
public interface BookingSlotRepository extends JpaRepository<BookingSlot, Long> { | ||
|
||
List<BookingSlot> findAllByPlaceIdAndDate(Long placeId, LocalDate date); | ||
|
||
Optional<BookingSlot> findFirstByPlaceIdAndDateAndTimeAndIsBookedFalse(Long placeId, | ||
LocalDate date, LocalTime time); | ||
} |
11 changes: 11 additions & 0 deletions
11
nowait-api/src/main/java/com/nowait/booking/dto/response/BookingRes.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,21 @@ | ||
package com.nowait.booking.dto.response; | ||
|
||
import com.nowait.booking.domain.model.Booking; | ||
import com.nowait.booking.domain.model.BookingSlot; | ||
|
||
public record BookingRes( | ||
Long bookingId, | ||
String bookingStatus, | ||
boolean depositRequired, | ||
boolean confirmRequired | ||
) { | ||
|
||
public static BookingRes of(Booking booking, BookingSlot slot) { | ||
return new BookingRes( | ||
booking.getId(), | ||
booking.getStatus().getDescription(), | ||
slot.isDepositRequired(), | ||
slot.isConfirmRequired() | ||
); | ||
} | ||
} |
10 changes: 10 additions & 0 deletions
10
nowait-api/src/main/java/com/nowait/common/config/JpaConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.nowait.common.config; | ||
|
||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.data.jpa.repository.config.EnableJpaAuditing; | ||
|
||
@Configuration | ||
@EnableJpaAuditing | ||
public class JpaConfig { | ||
|
||
} |
22 changes: 22 additions & 0 deletions
22
nowait-api/src/main/java/com/nowait/common/domain/model/BaseTimeEntity.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package com.nowait.common.domain.model; | ||
|
||
import jakarta.persistence.Column; | ||
import jakarta.persistence.EntityListeners; | ||
import jakarta.persistence.MappedSuperclass; | ||
import java.time.LocalDateTime; | ||
import org.springframework.data.annotation.CreatedDate; | ||
import org.springframework.data.annotation.LastModifiedDate; | ||
import org.springframework.data.jpa.domain.support.AuditingEntityListener; | ||
|
||
@MappedSuperclass | ||
@EntityListeners(AuditingEntityListener.class) | ||
public class BaseTimeEntity { | ||
|
||
@CreatedDate | ||
@Column(name = "created_at", nullable = false, updatable = false) | ||
private LocalDateTime createdAt; | ||
|
||
@LastModifiedDate | ||
@Column(name = "updated_at", nullable = false) | ||
private LocalDateTime updatedAt; | ||
} |
9 changes: 9 additions & 0 deletions
9
nowait-api/src/main/java/com/nowait/common/event/BookedEvent.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package com.nowait.common.event; | ||
|
||
public record BookedEvent( | ||
Long bookingId, | ||
Long placeId, | ||
Long userId | ||
) { | ||
|
||
} |
Oops, something went wrong.