Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
2606d59
feat: 객실재고 날짜 확인 기능 구현
korjun1993 May 6, 2023
fbf0d2a
feat: 객실재고량 확인 기능, 재고감소기능 추가
korjun1993 May 6, 2023
7413e20
feat: 예약기능 추가
korjun1993 May 6, 2023
23187ad
feat: 예약확정 기능 추가
korjun1993 May 6, 2023
d48b2a7
feat: 결제도메인 추가 (리뷰필요)
korjun1993 May 6, 2023
f8536c4
feat: 결제, 예약 관련 에러코드 추가
korjun1993 May 6, 2023
d2db93a
feat: 객실조회쿼리 수정
korjun1993 May 6, 2023
e1140bc
feat: 객실재고관리를 위한 테스트코드 추가
korjun1993 May 6, 2023
6ce929b
feat: Accommodation 연관관계 편의메서드 수정
korjun1993 May 9, 2023
8b95edc
feat: CheckDate 생성자 추가
korjun1993 May 10, 2023
1563ec0
test: CheckDate 테스트코드 추가
korjun1993 May 10, 2023
348c56c
fix: GuestInfo 도메인 필드 제거
korjun1993 May 10, 2023
2aa306c
fix: Inventory 유효성 검사 기능을 서비스 레이어로 이동
korjun1993 May 10, 2023
17beb26
fix: 재고감소 기능 -> 상태(quantity)를 변경하는 로직으로 수정
korjun1993 May 10, 2023
057c80e
feat: 예약 확정 기능 추가
korjun1993 May 10, 2023
9af464e
test: 객실품절검사, 객실재고기능 테스트
korjun1993 May 10, 2023
bea9922
fix: Reservation 생성자 변경 및 validate 로직 서비스 계층으로 이동
korjun1993 May 10, 2023
ded6691
fix: CreateReservationRequestDto 클래스 GuestInfo 구현하도록 수정
korjun1993 May 11, 2023
458f001
feat: 객실,예약,결제 관련 에러코드 추가
korjun1993 May 11, 2023
07707fd
feat: Payment 피드백 반영 + 결제시간초과 검사 기능 추가
korjun1993 May 11, 2023
50b682e
feat: 재고 계산 기능 -> 매개변수를 받아서 해당 값만큼 더하도록 수정
korjun1993 May 11, 2023
722f7f3
feat: 재고 계산 기능 -> 매개변수를 받아서 해당 값만큼 더하도록 수정
korjun1993 May 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.hotelJava.common.embeddable.Address;
import com.hotelJava.common.util.BaseTimeEntity;
import com.hotelJava.picture.domain.Picture;
import com.hotelJava.picture.domain.PictureType;
import com.hotelJava.reservation.domain.ReservationStatus;
import com.hotelJava.room.domain.Room;
import jakarta.persistence.CascadeType;
Expand Down Expand Up @@ -84,11 +85,12 @@ public Accommodation updateAccommodation(
// == 연관관계 편의 메소드 ==//
public void setPicture(Picture picture) {
this.picture = picture;
picture.setPictureType(PictureType.ACCOMMODATION);
picture.setAccommodation(this);
}

public void createAccommodation(List<Room> rooms, Picture accommodationPicture) {
this.picture = accommodationPicture;
setPicture(accommodationPicture);
this.rooms.addAll(rooms);
rooms.forEach(room -> room.setAccommodation(this));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,13 @@ public class CheckDate {

@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate checkOutDate;

public CheckDate(LocalDate checkInDate, int duration) {
this.checkInDate = checkInDate;
this.checkOutDate = checkInDate.plusDays(duration);
}

public boolean matches(LocalDate date) {
return date.isEqual(checkInDate) || (date.isAfter(checkInDate) && date.isBefore(checkOutDate));
}
}
18 changes: 15 additions & 3 deletions app/src/main/java/com/hotelJava/common/error/ErrorCode.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,23 @@ public enum ErrorCode {
DUPLICATED_NAME_FOUND(409, "숙소명이 이미 존재합니다."),
NO_MINIMUM_PRICE_FOUND(500, "숙소의 최소 가격을 찾을 수 없습니다."),

// 객실 관련 에러
ROOM_NOT_FOUND(404, "해당 객실이 존재하지 않습니다"),

// 예약 관련 에러
OUT_OF_STOCK(400, "재고 수량이 부족합니다"),
OVER_MAX_OCCUPANCY(400, "객실 최대 인원을 초과하였습니다"),
RESERVATION_NOT_FOUND(404, "결제 대기중인 예약을 찾을 수 없습니다"),

// 결제 관련 에러
PAYMENT_FAIL(400, "결제 오류"),
PAYMENT_TIME_OUT(408, "결제 유효 시간을 초과하였습니다"),

// 클라이언트 에러
BAD_REQUEST_ERROR(400, "요청값이 잘못되었습니다."),
BAD_REQUEST_ERROR(400, "요청값이 잘못되었습니다"),

// 서버 에러
INTERNAL_SERVER_ERROR(500, "요청을 정상 처리하지 못하였습니다.");
INTERNAL_SERVER_ERROR(500, "요청을 정상 처리하지 못하였습니다");

private final int code;
private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
package com.hotelJava.inventory;
package com.hotelJava.inventory.domain;

import com.hotelJava.common.util.BaseTimeEntity;
import com.hotelJava.room.domain.Room;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import java.time.LocalDate;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Entity
@Getter
@Setter
Expand All @@ -25,11 +30,28 @@ public class Inventory extends BaseTimeEntity {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private Long accommodationId;
@ManyToOne
@JoinColumn(name = "room_id")
private Room room;

private Long roomId;

private LocalDate date;

private long quantity;

public Inventory(LocalDate date, long quantity) {
this.date = date;
this.quantity = quantity;
}

public boolean isZeroQuantity() {
if (quantity <= 0) {
log.info("quantity at {} is 0", date);
return true;
}
return false;
}

public void calcQuantity(int value) {
quantity += value;
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.hotelJava.inventory.repository;

import com.hotelJava.inventory.Inventory;
import com.hotelJava.inventory.domain.Inventory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;import java.util.List;

@Repository
public interface InventoryRepository extends JpaRepository<Inventory, Long> {

List<Inventory> findByAccommodationIdAndRoomId(Long accommodationId, Long roomId);
List<Inventory> findByRoomId(Long roomId);
}
63 changes: 63 additions & 0 deletions app/src/main/java/com/hotelJava/payment/domain/Payment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.hotelJava.payment.domain;

import com.hotelJava.reservation.domain.Reservation;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToOne;
import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Entity
@Getter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Payment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private int amount;

@Enumerated(EnumType.STRING)
private PaymentType paymentType;

private LocalDateTime paymentDate;

@Enumerated(EnumType.STRING)
@Default
private PaymentStatus status = PaymentStatus.WAITING;

@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "reservation_id")
private Reservation reservation;

public Payment(int amount) {
this.amount = amount;
}

public PaymentStatus approve(PaymentResult paymentResult) {
if (paymentResult.isPayed(amount)) {
return status = PaymentStatus.COMPLETE;
}
log.info("payment fail");
return status = PaymentStatus.ERROR;
}

public boolean isExpired() {
return status != PaymentStatus.WAITING;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.hotelJava.payment.domain;

public interface PaymentResult {
boolean isPayed(int money);
}
15 changes: 15 additions & 0 deletions app/src/main/java/com/hotelJava/payment/domain/PaymentStatus.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.hotelJava.payment.domain;

public enum PaymentStatus {
WAITING("결제대기"),
COMPLETE("결제완료"),
CANCEL("결제취소"),
ERROR("결제오류"),
TIMEOUT("결제시간초과");

private final String label;

PaymentStatus(String label) {
this.label = label;
}
}
14 changes: 14 additions & 0 deletions app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.hotelJava.reservation.domain;

import com.hotelJava.common.embeddable.CheckDate;

public interface GuestInfo {

String getGuestName();

String getGuestPhone();

int getNumberOfGuests();

CheckDate getCheckDate();
}
82 changes: 60 additions & 22 deletions app/src/main/java/com/hotelJava/reservation/domain/Reservation.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,47 @@
import com.hotelJava.common.embeddable.CheckDate;
import com.hotelJava.common.util.BaseTimeEntity;
import com.hotelJava.member.domain.Member;
import com.hotelJava.payment.domain.PaymentType;
import com.hotelJava.payment.domain.Payment;
import com.hotelJava.payment.domain.PaymentResult;
import com.hotelJava.room.domain.Room;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.*;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
public class Reservation extends BaseTimeEntity {
public class Reservation extends BaseTimeEntity implements GuestInfo {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

private String reservationNo;

private String accommodationName;

private String roomName;
@Builder.Default
@Enumerated(EnumType.STRING)
private ReservationStatus status = ReservationStatus.PAYMENT_PENDING;

@Embedded private CheckDate checkDate;

private int numberOfGuests;

@Enumerated(EnumType.STRING)
private PaymentType paymentType;
private String guestName;

private String phoneNumber;
private String guestPhone;

@Enumerated(EnumType.STRING)
private ReservationStatus status;
@OneToOne(fetch = FetchType.LAZY, mappedBy = "reservation", cascade = CascadeType.ALL)
private Payment payment;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
Expand All @@ -61,4 +52,51 @@ public class Reservation extends BaseTimeEntity {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "room_id")
private Room room;

public Reservation(Member member, Room room, String reservationNo, GuestInfo guestInfo) {
this.member = member;
this.room = room;
this.reservationNo = reservationNo;
this.checkDate = guestInfo.getCheckDate();
this.guestName = guestInfo.getGuestName();
this.guestPhone = guestInfo.getGuestPhone();
this.numberOfGuests = guestInfo.getNumberOfGuests();
this.payment = new Payment(room.calcPrice());
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.paymentCascade 가 보이지 않는데, 잘 작동하던가요? 저도 확신이 없네요..

}

public Reservation confirm(PaymentResult paymentResult) {
payment.approve(paymentResult);
status = ReservationStatus.RESERVATION_COMPLETED;
return this;
}

public void consumeInventory() {
room.calcInventory(checkDate, -1);
}

public void restoreInventory() {
room.calcInventory(checkDate, 1);
}

public boolean isInvalidReservation() {
if (room.isNotEnoughInventoryAtCheckDate(checkDate)) {
log.info("room stock is not enough. payment declined");
return true;
}

if (room.isOverMaxOccupancy(numberOfGuests)) {
log.info("guest number is over max occupancy. payment declined");
return true;
}

return false;
}

public boolean isExpiredPayment() {
if (payment.isExpired()) {
log.info("payment time out. payment declined");
return true;
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ public enum ReservationStatus {
RESERVATION_AVAILABLE("예약가능"),
RESERVATION_COMPLETED("예약완료"),
RESERVATION_CANCEL("예약취소"),
SALES_COMPLETED("판매완료");
SALES_COMPLETED("판매완료"),
PAYMENT_PENDING("결제대기");

private final String label;
}
Loading