From 2606d593271a002f56d32dd6d92bdfb754a0a102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Sun, 7 May 2023 01:10:20 +0900 Subject: [PATCH 01/22] =?UTF-8?q?feat:=20=EA=B0=9D=EC=8B=A4=EC=9E=AC?= =?UTF-8?q?=EA=B3=A0=20=EB=82=A0=EC=A7=9C=20=ED=99=95=EC=9D=B8=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/hotelJava/common/embeddable/CheckDate.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/hotelJava/common/embeddable/CheckDate.java b/app/src/main/java/com/hotelJava/common/embeddable/CheckDate.java index a10cea5..8cedaaa 100644 --- a/app/src/main/java/com/hotelJava/common/embeddable/CheckDate.java +++ b/app/src/main/java/com/hotelJava/common/embeddable/CheckDate.java @@ -21,4 +21,8 @@ public class CheckDate { @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate checkOutDate; + + public boolean matches(LocalDate date) { + return date.isEqual(checkInDate) || (date.isAfter(checkInDate) && date.isBefore(checkOutDate)); + } } From fbf0d2a7a21bc60295a15d129f83b7759102943f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Sun, 7 May 2023 01:13:38 +0900 Subject: [PATCH 02/22] =?UTF-8?q?feat:=20=EA=B0=9D=EC=8B=A4=EC=9E=AC?= =?UTF-8?q?=EA=B3=A0=EB=9F=89=20=ED=99=95=EC=9D=B8=20=EA=B8=B0=EB=8A=A5,?= =?UTF-8?q?=20=EC=9E=AC=EA=B3=A0=EA=B0=90=EC=86=8C=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hotelJava/inventory/Inventory.java | 43 +++++++++++++++++-- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/hotelJava/inventory/Inventory.java b/app/src/main/java/com/hotelJava/inventory/Inventory.java index e7a462c..83d39d1 100644 --- a/app/src/main/java/com/hotelJava/inventory/Inventory.java +++ b/app/src/main/java/com/hotelJava/inventory/Inventory.java @@ -1,18 +1,26 @@ package com.hotelJava.inventory; +import com.hotelJava.common.embeddable.CheckDate; +import com.hotelJava.common.error.ErrorCode; +import com.hotelJava.common.error.exception.BadRequestException; 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 java.time.LocalDate; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; 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 @@ -25,11 +33,38 @@ 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 isEnoughQuantity() { + if (quantity <= 0) { + log.error("quantity at {} is 0", date); + return false; + } + return true; + } + + public void validate() { + if (!isEnoughQuantity()) { + throw new BadRequestException(ErrorCode.OUT_OF_STOCK); + } + } + + public Inventory reduceQuantity(CheckDate checkDate) { + if (checkDate.matches(date)) { + validate(); + return new Inventory(date, quantity - 1); + } + return this; + } } From 7413e205c1fdfa9ef80fc69f2fbef17b870d7d93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Sun, 7 May 2023 01:19:01 +0900 Subject: [PATCH 03/22] =?UTF-8?q?feat:=20=EC=98=88=EC=95=BD=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80=20-=20=EC=B2=B4=ED=81=AC?= =?UTF-8?q?=EC=9D=B8=20=EA=B8=B0=EA=B0=84=EC=9D=98=20=EA=B0=9D=EC=8B=A4?= =?UTF-8?q?=EB=93=A4=EC=97=90=20=EB=8C=80=ED=95=98=EC=97=AC=20"=EA=B0=9D?= =?UTF-8?q?=EC=8B=A4=EC=98=88=EC=95=BD=EA=B0=80=EB=8A=A5=EC=97=AC=EB=B6=80?= =?UTF-8?q?=20=ED=99=95=EC=9D=B8"=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20=EC=B2=B4=ED=81=AC=EC=9D=B8=20=EA=B8=B0?= =?UTF-8?q?=EA=B0=84=EC=9D=98=20=EA=B0=9D=EC=8B=A4=EB=93=A4=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=98=EC=97=AC=20"=EC=9E=AC=EA=B3=A0=20=EA=B0=90?= =?UTF-8?q?=EC=86=8C"=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20-=20?= =?UTF-8?q?=EC=98=88=EC=95=BD=EA=B0=9D=EC=B2=B4=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/domain/GuestInfo.java | 12 ++++ .../java/com/hotelJava/room/domain/Room.java | 56 +++++++++++++++---- 2 files changed, 58 insertions(+), 10 deletions(-) create mode 100644 app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java diff --git a/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java b/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java new file mode 100644 index 0000000..3f2626a --- /dev/null +++ b/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java @@ -0,0 +1,12 @@ +package com.hotelJava.reservation.domain; + +import com.hotelJava.common.embeddable.CheckDate; +import com.hotelJava.member.domain.Member; + +public interface GuestInfo { + Member getMember(); + + int getNumberOfGuests(); + + CheckDate getCheckDate(); +} diff --git a/app/src/main/java/com/hotelJava/room/domain/Room.java b/app/src/main/java/com/hotelJava/room/domain/Room.java index f5bb7fd..b75b94c 100644 --- a/app/src/main/java/com/hotelJava/room/domain/Room.java +++ b/app/src/main/java/com/hotelJava/room/domain/Room.java @@ -1,12 +1,13 @@ package com.hotelJava.room.domain; import com.hotelJava.accommodation.domain.Accommodation; -import com.hotelJava.common.embeddable.CheckTime; +import com.hotelJava.common.embeddable.CheckDate; import com.hotelJava.common.util.BaseTimeEntity; +import com.hotelJava.inventory.Inventory; import com.hotelJava.picture.domain.Picture; import com.hotelJava.reservation.domain.Reservation; +import com.hotelJava.reservation.domain.GuestInfo; import jakarta.persistence.CascadeType; -import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.GeneratedValue; @@ -17,13 +18,16 @@ import jakarta.persistence.OneToMany; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; 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 @@ -46,8 +50,6 @@ public class Room extends BaseTimeEntity { @JoinColumn(name = "accommodation_id") // accommodation_id 외래 키로 연관관계를 맺는다. private Accommodation accommodation; - @Embedded private CheckTime checkTime; - @OneToMany(mappedBy = "room", cascade = CascadeType.ALL) @Builder.Default private List pictures = new ArrayList<>(); @@ -58,21 +60,55 @@ public class Room extends BaseTimeEntity { @OneToMany(mappedBy = "room", cascade = CascadeType.ALL) @Builder.Default - private List roomAvailabilities = new ArrayList<>(); + private List inventories = new ArrayList<>(); + + public Reservation reserve(GuestInfo info) { + Reservation reservation = new Reservation(info); + reservations.add(reservation); + return reservation; + } + + public List reduceStock(CheckDate checkDate) { + return inventories.stream() + .map(item -> item.reduceQuantity(checkDate)) + .collect(Collectors.toList()); + } + + public boolean isAvailableReservation(int numberOfGuests, CheckDate checkDate) { + if (!isLowerMaxOccupancy(numberOfGuests)) { + log.info("numberOfGuests({}) is over maxOccupancy({})", numberOfGuests, maxOccupancy); + return false; + } + return isStockEnough(checkDate); + } + + public boolean isStockEnough(CheckDate checkDate) { + return inventories.stream() + .filter(i -> checkDate.matches(i.getDate())) + .allMatch(Inventory::isEnoughQuantity); + } + + public boolean isLowerMaxOccupancy(int guestNumber) { + return guestNumber <= maxOccupancy; + } + + public int calcPrice() { + return price; + } // == 연관관계 편의 메소드 ==// public void addPicture(Picture picture) { - this.pictures.add(picture); + pictures.add(picture); picture.setRoom(this); } public void addReservation(Reservation reservation) { - this.reservations.add(reservation); + reservations.add(reservation); reservation.setRoom(this); } - public void addRoomAvailability(RoomAvailability roomAvailability) { - this.roomAvailabilities.add(roomAvailability); - roomAvailability.setRoom(this); + public void addInventory(Inventory inventory) { + inventories.add(inventory); + inventory.setRoom(this); } } From 23187adba8797d2fb57069588f3fbb2c03a5bf49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Sun, 7 May 2023 01:22:13 +0900 Subject: [PATCH 04/22] =?UTF-8?q?feat:=20=EC=98=88=EC=95=BD=ED=99=95?= =?UTF-8?q?=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80=20-=20?= =?UTF-8?q?=EC=98=88=EC=95=BD=EC=97=90=20=EB=8C=80=ED=95=B4=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=20=EC=8A=B9=EC=9D=B8=20=EC=97=AC=EB=B6=80=EB=A5=BC=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=ED=9B=84,=20=EC=A0=95=EC=83=81=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=20=EC=83=81=ED=99=A9=EC=9D=B4=EB=9D=BC=EB=A9=B4=20?= =?UTF-8?q?=EC=9E=AC=EA=B3=A0=EB=A5=BC=20=EA=B0=90=EC=86=8C=EC=8B=9C?= =?UTF-8?q?=ED=82=A4=EA=B3=A0=20=EC=98=88=EC=95=BD=EC=83=81=ED=83=9C?= =?UTF-8?q?=EB=A5=BC=20=EB=B3=80=EA=B2=BD=EC=8B=9C=ED=82=A8=EB=8B=A4.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/domain/Reservation.java | 68 ++++++++++++------- .../reservation/domain/ReservationStatus.java | 3 +- 2 files changed, 44 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java b/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java index cf14894..14019ad 100644 --- a/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java +++ b/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java @@ -1,58 +1,46 @@ package com.hotelJava.reservation.domain; import com.hotelJava.common.embeddable.CheckDate; +import com.hotelJava.common.error.ErrorCode; +import com.hotelJava.common.error.exception.BadRequestException; 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.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.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 phoneNumber; - - @Enumerated(EnumType.STRING) - private ReservationStatus status; + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "payment_id") + private Payment payment; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id") @@ -61,4 +49,32 @@ public class Reservation extends BaseTimeEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "room_id") private Room room; + + public Reservation(GuestInfo info) { + this.member = info.getMember(); + this.checkDate = info.getCheckDate(); + this.numberOfGuests = info.getNumberOfGuests(); + this.payment = new Payment(room.calcPrice()); + } + + public Reservation confirm() { + validateReservation(); + if (!payment.isPaymentSuccess()) { + throw new BadRequestException(ErrorCode.PAYMENT_FAIL); + } + room.reduceStock(checkDate); + // TODO: 결제승인 + status = ReservationStatus.RESERVATION_COMPLETED; + // payment.approve(); + return this; + } + + public void validateReservation() { + if (!room.isAvailableReservation(numberOfGuests, checkDate)) { + // TODO: 결제승인거절 + // payment.decline(); + log.info("payment declined"); + throw new BadRequestException(ErrorCode.PAYMENT_FAIL); + } + } } diff --git a/app/src/main/java/com/hotelJava/reservation/domain/ReservationStatus.java b/app/src/main/java/com/hotelJava/reservation/domain/ReservationStatus.java index 6bc2e2d..64897c5 100644 --- a/app/src/main/java/com/hotelJava/reservation/domain/ReservationStatus.java +++ b/app/src/main/java/com/hotelJava/reservation/domain/ReservationStatus.java @@ -10,7 +10,8 @@ public enum ReservationStatus { RESERVATION_AVAILABLE("예약가능"), RESERVATION_COMPLETED("예약완료"), RESERVATION_CANCEL("예약취소"), - SALES_COMPLETED("판매완료"); + SALES_COMPLETED("판매완료"), + PAYMENT_PENDING("결제대기"); private final String label; } From d48b2a7956e45fc1f48451cb4e187d6bf63fd184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Sun, 7 May 2023 01:23:19 +0900 Subject: [PATCH 05/22] =?UTF-8?q?feat:=20=EA=B2=B0=EC=A0=9C=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20=EC=B6=94=EA=B0=80=20(=EB=A6=AC=EB=B7=B0?= =?UTF-8?q?=ED=95=84=EC=9A=94)=20-=20=EC=99=B8=EB=B6=80=20=ED=8F=AC?= =?UTF-8?q?=ED=8A=B8=EC=9B=90=20API=EC=99=80=20=EC=9D=98=EC=A1=B4=EC=84=B1?= =?UTF-8?q?=EC=9D=84=20=EB=B6=84=EB=A6=AC=EC=8B=9C=ED=82=A4=EB=8A=94=20?= =?UTF-8?q?=EB=B2=95=EC=97=90=20=EB=8C=80=ED=95=B4=20=EC=83=81=EC=9D=98=20?= =?UTF-8?q?=ED=95=84=EC=9A=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hotelJava/payment/domain/Payment.java | 43 +++++++++++++++++++ .../payment/domain/PaymentStatus.java | 14 ++++++ 2 files changed, 57 insertions(+) create mode 100644 app/src/main/java/com/hotelJava/payment/domain/Payment.java create mode 100644 app/src/main/java/com/hotelJava/payment/domain/PaymentStatus.java diff --git a/app/src/main/java/com/hotelJava/payment/domain/Payment.java b/app/src/main/java/com/hotelJava/payment/domain/Payment.java new file mode 100644 index 0000000..c3ff07f --- /dev/null +++ b/app/src/main/java/com/hotelJava/payment/domain/Payment.java @@ -0,0 +1,43 @@ +package com.hotelJava.payment.domain; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import java.time.LocalDateTime; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder.Default; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor +public class Payment { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + private int amount; + private PaymentType paymentType; + private LocalDateTime paymentDate; + +// @Default private PaymentStatus status = PaymentStatus.WAITING; + + public Payment(int amount) { + this.amount = amount; + } + + // public void changeStatus(PaymentStatus status) { + // this.status = status; + // } + + public boolean isPaymentSuccess() { + // TODO: 포트원 API 로부터 정상 결제됐는지 확인 + // if (정상처리) this.status = PaymentStatus.COMPLETE; + // return status == PaymentStatus.COMPLETE; + return true; + } +} diff --git a/app/src/main/java/com/hotelJava/payment/domain/PaymentStatus.java b/app/src/main/java/com/hotelJava/payment/domain/PaymentStatus.java new file mode 100644 index 0000000..ffa823d --- /dev/null +++ b/app/src/main/java/com/hotelJava/payment/domain/PaymentStatus.java @@ -0,0 +1,14 @@ +package com.hotelJava.payment.domain; + +public enum PaymentStatus { + WAITING("결제대기"), + COMPLETE("결제완료"), + CANCEL("결제취소"), + ERROR("결제오류"); + + private final String label; + + PaymentStatus(String label) { + this.label = label; + } +} From f8536c4ee5ba4154028078f901845099d86f62c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Sun, 7 May 2023 01:24:27 +0900 Subject: [PATCH 06/22] =?UTF-8?q?feat:=20=EA=B2=B0=EC=A0=9C,=20=EC=98=88?= =?UTF-8?q?=EC=95=BD=20=EA=B4=80=EB=A0=A8=20=EC=97=90=EB=9F=AC=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/hotelJava/common/error/ErrorCode.java | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/hotelJava/common/error/ErrorCode.java b/app/src/main/java/com/hotelJava/common/error/ErrorCode.java index deae3ff..0330d98 100644 --- a/app/src/main/java/com/hotelJava/common/error/ErrorCode.java +++ b/app/src/main/java/com/hotelJava/common/error/ErrorCode.java @@ -25,11 +25,18 @@ public enum ErrorCode { DUPLICATED_NAME_FOUND(409, "숙소명이 이미 존재합니다."), NO_MINIMUM_PRICE_FOUND(500, "숙소의 최소 가격을 찾을 수 없습니다."), + // 예약 관련 에러 + OUT_OF_STOCK(400, "재고 수량이 부족합니다"), + OVER_MAX_OCCUPANCY(400, "객실 최대 인원을 초과하였습니다"), + + // 결제 관련 에러 + PAYMENT_FAIL(400, "결제 오류"), + // 클라이언트 에러 - BAD_REQUEST_ERROR(400, "요청값이 잘못되었습니다."), - + BAD_REQUEST_ERROR(400, "요청값이 잘못되었습니다"), + // 서버 에러 - INTERNAL_SERVER_ERROR(500, "요청을 정상 처리하지 못하였습니다."); + INTERNAL_SERVER_ERROR(500, "요청을 정상 처리하지 못하였습니다"); private final int code; private final String message; From d2db93a1c4e1c1ec7ca3cb8b4cf61a49eb7997b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Sun, 7 May 2023 01:25:05 +0900 Subject: [PATCH 07/22] =?UTF-8?q?feat:=20=EA=B0=9D=EC=8B=A4=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EC=BF=BC=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hotelJava/inventory/repository/InventoryRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/hotelJava/inventory/repository/InventoryRepository.java b/app/src/main/java/com/hotelJava/inventory/repository/InventoryRepository.java index 78dcb4b..3cba3c9 100644 --- a/app/src/main/java/com/hotelJava/inventory/repository/InventoryRepository.java +++ b/app/src/main/java/com/hotelJava/inventory/repository/InventoryRepository.java @@ -7,5 +7,5 @@ @Repository public interface InventoryRepository extends JpaRepository { - List findByAccommodationIdAndRoomId(Long accommodationId, Long roomId); + List findByRoomId(Long roomId); } From e1140bcec90a79b6f69ab4bb8afeeafc458b661e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Sun, 7 May 2023 01:26:13 +0900 Subject: [PATCH 08/22] =?UTF-8?q?feat:=20=EA=B0=9D=EC=8B=A4=EC=9E=AC?= =?UTF-8?q?=EA=B3=A0=EA=B4=80=EB=A6=AC=EB=A5=BC=20=EC=9C=84=ED=95=9C=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hotelJava/inventory/InventoryTest.java | 70 +++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 app/src/test/java/com/hotelJava/inventory/InventoryTest.java diff --git a/app/src/test/java/com/hotelJava/inventory/InventoryTest.java b/app/src/test/java/com/hotelJava/inventory/InventoryTest.java new file mode 100644 index 0000000..26bcb09 --- /dev/null +++ b/app/src/test/java/com/hotelJava/inventory/InventoryTest.java @@ -0,0 +1,70 @@ +package com.hotelJava.inventory; + +import static org.assertj.core.api.Assertions.assertThat; + +import com.hotelJava.TestFixture; +import com.hotelJava.common.embeddable.CheckDate; +import com.hotelJava.common.error.exception.BadRequestException; +import java.time.LocalDate; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class InventoryTest { + + @Test + @DisplayName("재고가 1보다 많다면 true 를 반환한다") + void 재고검사() { + // given + Inventory inventory = TestFixture.getInventory(TestFixture.getRoom(1), LocalDate.now(), 10); + + // when + boolean enoughQuantity = inventory.isEnoughQuantity(); + + // then + assertThat(enoughQuantity).isTrue(); + } + + @Test + @DisplayName("재고가 1보다 적다면 false 를 반환한다") + void 재고검사_재고부족() { + // given + Inventory inventory = TestFixture.getInventory(TestFixture.getRoom(1), LocalDate.now(), 10); + + // when + boolean enoughQuantity = inventory.isEnoughQuantity(); + + // then + assertThat(enoughQuantity).isTrue(); + } + + @Test + @DisplayName("숙박 기간에 해당하는 객실상품이고 재고가 1보다 크다면 재고를 1 감소시킨다") + void 재고감소() { + // given + Inventory inventory = TestFixture.getInventory(TestFixture.getRoom(1), LocalDate.now(), 10); + LocalDate checkin = LocalDate.now(); + LocalDate checkout = checkin.plusDays(1); + CheckDate checkDate = new CheckDate(checkin, checkout); + + // when + long expect = inventory.getQuantity() - 1; + + // then + assertThat(inventory.reduceQuantity(checkDate).getQuantity()).isEqualTo(expect); + } + + @Test + @DisplayName("체크인 ~ 체크아웃 기간의 객실재고 중 1보다 작은 날이 하루라도 존재하면 예외가 발생한다") + void 재고감소_예외발생_재고부족() { + // given + Inventory inventory = TestFixture.getInventory(TestFixture.getRoom(1), LocalDate.now(), 0); + LocalDate checkin = LocalDate.now(); + LocalDate checkout = checkin.plusDays(1); + CheckDate checkDate = new CheckDate(checkin, checkout); + + // when, then + Assertions.assertThatThrownBy(() -> inventory.reduceQuantity(checkDate)) + .isInstanceOf(BadRequestException.class); + } +} From 6ce929bfa22318f571652e8ca6444f562f405806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Tue, 9 May 2023 12:47:45 +0900 Subject: [PATCH 09/22] =?UTF-8?q?feat:=20Accommodation=20=EC=97=B0?= =?UTF-8?q?=EA=B4=80=EA=B4=80=EA=B3=84=20=ED=8E=B8=EC=9D=98=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hotelJava/accommodation/domain/Accommodation.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/hotelJava/accommodation/domain/Accommodation.java b/app/src/main/java/com/hotelJava/accommodation/domain/Accommodation.java index 296557b..33cb302 100644 --- a/app/src/main/java/com/hotelJava/accommodation/domain/Accommodation.java +++ b/app/src/main/java/com/hotelJava/accommodation/domain/Accommodation.java @@ -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; @@ -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 rooms, Picture accommodationPicture) { - this.picture = accommodationPicture; + setPicture(accommodationPicture); this.rooms.addAll(rooms); rooms.forEach(room -> room.setAccommodation(this)); } From 8b95edc6818178cf788ad74e75c0b5dacce3c0ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Wed, 10 May 2023 23:32:50 +0900 Subject: [PATCH 10/22] =?UTF-8?q?feat:=20CheckDate=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/com/hotelJava/common/embeddable/CheckDate.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/com/hotelJava/common/embeddable/CheckDate.java b/app/src/main/java/com/hotelJava/common/embeddable/CheckDate.java index 8cedaaa..8c27eff 100644 --- a/app/src/main/java/com/hotelJava/common/embeddable/CheckDate.java +++ b/app/src/main/java/com/hotelJava/common/embeddable/CheckDate.java @@ -22,6 +22,11 @@ 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)); } From 1563ec04d204b48e94c05b0b865a72d608fcd565 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Wed, 10 May 2023 23:33:21 +0900 Subject: [PATCH 11/22] =?UTF-8?q?test:=20CheckDate=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/embeddable/CheckDateTest.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 app/src/test/java/com/hotelJava/common/embeddable/CheckDateTest.java diff --git a/app/src/test/java/com/hotelJava/common/embeddable/CheckDateTest.java b/app/src/test/java/com/hotelJava/common/embeddable/CheckDateTest.java new file mode 100644 index 0000000..80e09ee --- /dev/null +++ b/app/src/test/java/com/hotelJava/common/embeddable/CheckDateTest.java @@ -0,0 +1,31 @@ +package com.hotelJava.common.embeddable; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class CheckDateTest { + + @Test + @DisplayName("주어진 날짜가 숙박 기간 사이의 날짜라면 true 를 반환한다") + void 숙박기간_날짜비교_true() { + // given + CheckDate checkDate = new CheckDate(LocalDate.of(2023, 5, 10), 2); + + // then + assertThat(checkDate.matches(LocalDate.of(2023, 5, 10))).isTrue(); + assertThat(checkDate.matches(LocalDate.of(2023, 5, 11))).isTrue(); + } + + @Test + @DisplayName("주어진 날짜가 숙박 기간 사이의 날짜가 아니라면 false 를 반환한다") + void 숙박기간_날짜비교_false() { + // given + CheckDate checkDate = new CheckDate(LocalDate.of(2023, 5, 10), 2); + + // then + assertThat(checkDate.matches(LocalDate.of(2023, 5, 12))).isFalse(); + } +} From 348c56c894462a57925dcea40ed2433e28247530 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Wed, 10 May 2023 23:33:57 +0900 Subject: [PATCH 12/22] =?UTF-8?q?fix:=20GuestInfo=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=ED=95=84=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/hotelJava/reservation/domain/GuestInfo.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java b/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java index 3f2626a..a5fe66d 100644 --- a/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java +++ b/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java @@ -1,10 +1,12 @@ package com.hotelJava.reservation.domain; import com.hotelJava.common.embeddable.CheckDate; -import com.hotelJava.member.domain.Member; public interface GuestInfo { - Member getMember(); + + String getName(); + + String getPhone(); int getNumberOfGuests(); From 2aa306c42fe59b448247bb50992b5744433970fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Wed, 10 May 2023 23:41:04 +0900 Subject: [PATCH 13/22] =?UTF-8?q?fix:=20Inventory=20=EC=9C=A0=ED=9A=A8?= =?UTF-8?q?=EC=84=B1=20=EA=B2=80=EC=82=AC=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EB=A0=88=EC=9D=B4=EC=96=B4?= =?UTF-8?q?=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 재고검사 기능의 테스트는 서비스레이어 테스트코드에서 수행 예정 --- .../inventory/{ => domain}/Inventory.java | 29 +++----- .../repository/InventoryRepository.java | 2 +- .../hotelJava/inventory/InventoryTest.java | 70 ------------------- 3 files changed, 9 insertions(+), 92 deletions(-) rename app/src/main/java/com/hotelJava/inventory/{ => domain}/Inventory.java (62%) delete mode 100644 app/src/test/java/com/hotelJava/inventory/InventoryTest.java diff --git a/app/src/main/java/com/hotelJava/inventory/Inventory.java b/app/src/main/java/com/hotelJava/inventory/domain/Inventory.java similarity index 62% rename from app/src/main/java/com/hotelJava/inventory/Inventory.java rename to app/src/main/java/com/hotelJava/inventory/domain/Inventory.java index 83d39d1..b21e2c9 100644 --- a/app/src/main/java/com/hotelJava/inventory/Inventory.java +++ b/app/src/main/java/com/hotelJava/inventory/domain/Inventory.java @@ -1,17 +1,14 @@ -package com.hotelJava.inventory; +package com.hotelJava.inventory.domain; -import com.hotelJava.common.embeddable.CheckDate; -import com.hotelJava.common.error.ErrorCode; -import com.hotelJava.common.error.exception.BadRequestException; 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 java.time.LocalDate; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; +import java.time.LocalDate; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -46,25 +43,15 @@ public Inventory(LocalDate date, long quantity) { this.quantity = quantity; } - public boolean isEnoughQuantity() { + public boolean isZeroQuantity() { if (quantity <= 0) { - log.error("quantity at {} is 0", date); - return false; - } - return true; - } - - public void validate() { - if (!isEnoughQuantity()) { - throw new BadRequestException(ErrorCode.OUT_OF_STOCK); + log.info("quantity at {} is 0", date); + return true; } + return false; } - public Inventory reduceQuantity(CheckDate checkDate) { - if (checkDate.matches(date)) { - validate(); - return new Inventory(date, quantity - 1); - } - return this; + public void reduceQuantity() { + quantity--; } } diff --git a/app/src/main/java/com/hotelJava/inventory/repository/InventoryRepository.java b/app/src/main/java/com/hotelJava/inventory/repository/InventoryRepository.java index 3cba3c9..463f524 100644 --- a/app/src/main/java/com/hotelJava/inventory/repository/InventoryRepository.java +++ b/app/src/main/java/com/hotelJava/inventory/repository/InventoryRepository.java @@ -1,6 +1,6 @@ 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; diff --git a/app/src/test/java/com/hotelJava/inventory/InventoryTest.java b/app/src/test/java/com/hotelJava/inventory/InventoryTest.java deleted file mode 100644 index 26bcb09..0000000 --- a/app/src/test/java/com/hotelJava/inventory/InventoryTest.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.hotelJava.inventory; - -import static org.assertj.core.api.Assertions.assertThat; - -import com.hotelJava.TestFixture; -import com.hotelJava.common.embeddable.CheckDate; -import com.hotelJava.common.error.exception.BadRequestException; -import java.time.LocalDate; -import org.assertj.core.api.Assertions; -import org.junit.jupiter.api.DisplayName; -import org.junit.jupiter.api.Test; - -class InventoryTest { - - @Test - @DisplayName("재고가 1보다 많다면 true 를 반환한다") - void 재고검사() { - // given - Inventory inventory = TestFixture.getInventory(TestFixture.getRoom(1), LocalDate.now(), 10); - - // when - boolean enoughQuantity = inventory.isEnoughQuantity(); - - // then - assertThat(enoughQuantity).isTrue(); - } - - @Test - @DisplayName("재고가 1보다 적다면 false 를 반환한다") - void 재고검사_재고부족() { - // given - Inventory inventory = TestFixture.getInventory(TestFixture.getRoom(1), LocalDate.now(), 10); - - // when - boolean enoughQuantity = inventory.isEnoughQuantity(); - - // then - assertThat(enoughQuantity).isTrue(); - } - - @Test - @DisplayName("숙박 기간에 해당하는 객실상품이고 재고가 1보다 크다면 재고를 1 감소시킨다") - void 재고감소() { - // given - Inventory inventory = TestFixture.getInventory(TestFixture.getRoom(1), LocalDate.now(), 10); - LocalDate checkin = LocalDate.now(); - LocalDate checkout = checkin.plusDays(1); - CheckDate checkDate = new CheckDate(checkin, checkout); - - // when - long expect = inventory.getQuantity() - 1; - - // then - assertThat(inventory.reduceQuantity(checkDate).getQuantity()).isEqualTo(expect); - } - - @Test - @DisplayName("체크인 ~ 체크아웃 기간의 객실재고 중 1보다 작은 날이 하루라도 존재하면 예외가 발생한다") - void 재고감소_예외발생_재고부족() { - // given - Inventory inventory = TestFixture.getInventory(TestFixture.getRoom(1), LocalDate.now(), 0); - LocalDate checkin = LocalDate.now(); - LocalDate checkout = checkin.plusDays(1); - CheckDate checkDate = new CheckDate(checkin, checkout); - - // when, then - Assertions.assertThatThrownBy(() -> inventory.reduceQuantity(checkDate)) - .isInstanceOf(BadRequestException.class); - } -} From 17beb269ce0d300e6983b0990a10a7eb1851abfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Wed, 10 May 2023 23:44:12 +0900 Subject: [PATCH 14/22] =?UTF-8?q?fix:=20=EC=9E=AC=EA=B3=A0=EA=B0=90?= =?UTF-8?q?=EC=86=8C=20=EA=B8=B0=EB=8A=A5=20->=20=EC=83=81=ED=83=9C(quanti?= =?UTF-8?q?ty)=EB=A5=BC=20=EB=B3=80=EA=B2=BD=ED=95=98=EB=8A=94=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=EC=9C=BC=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/hotelJava/room/domain/Room.java | 36 ++++++------------- 1 file changed, 11 insertions(+), 25 deletions(-) diff --git a/app/src/main/java/com/hotelJava/room/domain/Room.java b/app/src/main/java/com/hotelJava/room/domain/Room.java index b75b94c..ef1f44a 100644 --- a/app/src/main/java/com/hotelJava/room/domain/Room.java +++ b/app/src/main/java/com/hotelJava/room/domain/Room.java @@ -3,10 +3,9 @@ import com.hotelJava.accommodation.domain.Accommodation; import com.hotelJava.common.embeddable.CheckDate; import com.hotelJava.common.util.BaseTimeEntity; -import com.hotelJava.inventory.Inventory; +import com.hotelJava.inventory.domain.Inventory; import com.hotelJava.picture.domain.Picture; import com.hotelJava.reservation.domain.Reservation; -import com.hotelJava.reservation.domain.GuestInfo; import jakarta.persistence.CascadeType; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; @@ -18,19 +17,16 @@ import jakarta.persistence.OneToMany; import java.util.ArrayList; import java.util.List; -import java.util.stream.Collectors; 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 @@ -62,30 +58,16 @@ public class Room extends BaseTimeEntity { @Builder.Default private List inventories = new ArrayList<>(); - public Reservation reserve(GuestInfo info) { - Reservation reservation = new Reservation(info); - reservations.add(reservation); - return reservation; - } - - public List reduceStock(CheckDate checkDate) { - return inventories.stream() - .map(item -> item.reduceQuantity(checkDate)) - .collect(Collectors.toList()); - } - - public boolean isAvailableReservation(int numberOfGuests, CheckDate checkDate) { - if (!isLowerMaxOccupancy(numberOfGuests)) { - log.info("numberOfGuests({}) is over maxOccupancy({})", numberOfGuests, maxOccupancy); - return false; - } - return isStockEnough(checkDate); + public void reduceStock(CheckDate checkDate) { + inventories.stream() + .filter(i -> checkDate.matches(i.getDate())) + .forEach(Inventory::reduceQuantity); } - public boolean isStockEnough(CheckDate checkDate) { + public boolean isStockOut(CheckDate checkDate) { return inventories.stream() .filter(i -> checkDate.matches(i.getDate())) - .allMatch(Inventory::isEnoughQuantity); + .anyMatch(Inventory::isZeroQuantity); } public boolean isLowerMaxOccupancy(int guestNumber) { @@ -97,6 +79,10 @@ public int calcPrice() { } // == 연관관계 편의 메소드 ==// + public void setAccommodation(Accommodation accommodation) { + this.accommodation = accommodation; + } + public void addPicture(Picture picture) { pictures.add(picture); picture.setRoom(this); From 057c80e7fdbeaa38417145031ef51b44baf8fc29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Wed, 10 May 2023 23:46:01 +0900 Subject: [PATCH 15/22] =?UTF-8?q?feat:=20=EC=98=88=EC=95=BD=20=ED=99=95?= =?UTF-8?q?=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hotelJava/payment/domain/Payment.java | 36 ++++++++++++----- .../payment/domain/PaymentResult.java | 5 +++ .../reservation/domain/Reservation.java | 39 +++++++++++-------- 3 files changed, 54 insertions(+), 26 deletions(-) create mode 100644 app/src/main/java/com/hotelJava/payment/domain/PaymentResult.java diff --git a/app/src/main/java/com/hotelJava/payment/domain/Payment.java b/app/src/main/java/com/hotelJava/payment/domain/Payment.java index c3ff07f..25f491c 100644 --- a/app/src/main/java/com/hotelJava/payment/domain/Payment.java +++ b/app/src/main/java/com/hotelJava/payment/domain/Payment.java @@ -1,18 +1,28 @@ package com.hotelJava.payment.domain; +import com.hotelJava.common.error.ErrorCode; +import com.hotelJava.common.error.exception.BadRequestException; +import com.hotelJava.reservation.domain.Reservation; 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.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 { @@ -21,23 +31,29 @@ public class Payment { private Long id; private int amount; + + @Enumerated(EnumType.STRING) private PaymentType paymentType; + private LocalDateTime paymentDate; -// @Default private PaymentStatus status = PaymentStatus.WAITING; + @Enumerated(EnumType.STRING) + @Default + private PaymentStatus status = PaymentStatus.WAITING; + + @OneToOne(mappedBy = "payment") + private Reservation reservation; public Payment(int amount) { this.amount = amount; } - // public void changeStatus(PaymentStatus status) { - // this.status = status; - // } - - public boolean isPaymentSuccess() { - // TODO: 포트원 API 로부터 정상 결제됐는지 확인 - // if (정상처리) this.status = PaymentStatus.COMPLETE; - // return status == PaymentStatus.COMPLETE; - return true; + public void approve(PaymentResult paymentResult) { + if (paymentResult.isPayed(amount)) { + status = PaymentStatus.COMPLETE; + } else { + status = PaymentStatus.ERROR; + throw new BadRequestException(ErrorCode.PAYMENT_FAIL); + } } } diff --git a/app/src/main/java/com/hotelJava/payment/domain/PaymentResult.java b/app/src/main/java/com/hotelJava/payment/domain/PaymentResult.java new file mode 100644 index 0000000..fdc9692 --- /dev/null +++ b/app/src/main/java/com/hotelJava/payment/domain/PaymentResult.java @@ -0,0 +1,5 @@ +package com.hotelJava.payment.domain; + +public interface PaymentResult { + boolean isPayed(int money); +} diff --git a/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java b/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java index 14019ad..b7eb730 100644 --- a/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java +++ b/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java @@ -6,13 +6,15 @@ import com.hotelJava.common.util.BaseTimeEntity; import com.hotelJava.member.domain.Member; import com.hotelJava.payment.domain.Payment; +import com.hotelJava.payment.domain.PaymentResult; import com.hotelJava.room.domain.Room; import jakarta.persistence.*; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; -import lombok.NoArgsConstructor;import lombok.Setter; +import lombok.NoArgsConstructor; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; @Slf4j @@ -38,6 +40,10 @@ public class Reservation extends BaseTimeEntity implements GuestInfo { private int numberOfGuests; + private String name; + + private String phone; + @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "payment_id") private Payment payment; @@ -50,30 +56,31 @@ public class Reservation extends BaseTimeEntity implements GuestInfo { @JoinColumn(name = "room_id") private Room room; - public Reservation(GuestInfo info) { - this.member = info.getMember(); - this.checkDate = info.getCheckDate(); - this.numberOfGuests = info.getNumberOfGuests(); + public Reservation(Member member, GuestInfo guestInfo) { + this.member = member; + this.checkDate = guestInfo.getCheckDate(); + this.name = guestInfo.getName(); + this.numberOfGuests = guestInfo.getNumberOfGuests(); + this.phone = guestInfo.getPhone(); this.payment = new Payment(room.calcPrice()); } - public Reservation confirm() { + public Reservation confirm(PaymentResult paymentResult) { validateReservation(); - if (!payment.isPaymentSuccess()) { - throw new BadRequestException(ErrorCode.PAYMENT_FAIL); - } + payment.approve(paymentResult); room.reduceStock(checkDate); - // TODO: 결제승인 status = ReservationStatus.RESERVATION_COMPLETED; - // payment.approve(); return this; } - public void validateReservation() { - if (!room.isAvailableReservation(numberOfGuests, checkDate)) { - // TODO: 결제승인거절 - // payment.decline(); - log.info("payment declined"); + private void validateReservation() { + if (room.isStockOut(checkDate)) { + log.info("room stock is not enough. payment declined"); + throw new BadRequestException(ErrorCode.PAYMENT_FAIL); + } + + if (!room.isLowerMaxOccupancy(numberOfGuests)) { + log.info("guest number is over max occupancy. payment declined"); throw new BadRequestException(ErrorCode.PAYMENT_FAIL); } } From 9af464e0d29f7623e77ca18721c7dd09b13e9bb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Wed, 10 May 2023 23:48:25 +0900 Subject: [PATCH 16/22] =?UTF-8?q?test:=20=EA=B0=9D=EC=8B=A4=ED=92=88?= =?UTF-8?q?=EC=A0=88=EA=B2=80=EC=82=AC,=20=EA=B0=9D=EC=8B=A4=EC=9E=AC?= =?UTF-8?q?=EA=B3=A0=EA=B8=B0=EB=8A=A5=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../test/java/com/hotelJava/TestFixture.java | 35 +++++----- .../com/hotelJava/room/domain/RoomTest.java | 67 +++++++++++++++++++ 2 files changed, 86 insertions(+), 16 deletions(-) create mode 100644 app/src/test/java/com/hotelJava/room/domain/RoomTest.java diff --git a/app/src/test/java/com/hotelJava/TestFixture.java b/app/src/test/java/com/hotelJava/TestFixture.java index f6c6973..7166469 100644 --- a/app/src/test/java/com/hotelJava/TestFixture.java +++ b/app/src/test/java/com/hotelJava/TestFixture.java @@ -4,7 +4,7 @@ import com.hotelJava.accommodation.domain.Accommodation; import com.hotelJava.accommodation.domain.AccommodationType; import com.hotelJava.common.embeddable.Address; -import com.hotelJava.inventory.Inventory; +import com.hotelJava.inventory.domain.Inventory; import com.hotelJava.member.domain.Grade; import com.hotelJava.member.domain.Member; import com.hotelJava.member.domain.Role; @@ -73,7 +73,7 @@ public static Picture getPicture() { return Picture.builder().pictureInfo(getPictureInfo()).build(); } - public static Accommodation getAccommodation(LocalDate start, int duration, int roomNumber) { + public static Accommodation getAccommodation(LocalDate from, int duration, int roomNumber) { Picture picture = getPicture(); Accommodation accommodation = Accommodation.builder() @@ -88,22 +88,23 @@ public static Accommodation getAccommodation(LocalDate start, int duration, int // mapping rooms & picture List rooms = new LinkedList<>(); for (int i = 0; i < roomNumber; i++) { - rooms.add(getRoom(faker.number().numberBetween(1, 5))); + int maxOccupancy = faker.number().numberBetween(1, 5); + int quantity = faker.number().numberBetween(1, 5); + rooms.add(getRoom(maxOccupancy, quantity, from, duration)); } accommodation.createAccommodation(rooms, picture); - // mapping inventory - - rooms.forEach( - room -> - start - .datesUntil(start.plusDays(duration)) - .forEach(date -> getInventory(room, date, faker.number().numberBetween(1, 5)))); - return accommodation; } - public static Room getRoom(int maxOccupancy) { + /** + * @param maxOccupancy 객실 최대 인원 + * @param quantity 객실 재고량 + * @param from 객실 재고를 언제부터 관리할 것인지 + * @param duration 객실 재고 보관 기간 + * @return 객실 및 객실의 재고 정보 + */ + public static Room getRoom(int maxOccupancy, int quantity, LocalDate from, int duration) { Picture picture = getPicture(); Room room = Room.builder() @@ -111,13 +112,15 @@ public static Room getRoom(int maxOccupancy) { .price(faker.number().numberBetween(50000, 100000)) .maxOccupancy(maxOccupancy) .build(); + room.addPicture(picture); + from.datesUntil(from.plusDays(duration)) + .forEach(d -> room.addInventory(getInventory(d, quantity))); + return room; } - public static Inventory getInventory(Room room, LocalDate date, int quantity) { - Inventory inventory = new Inventory(date, quantity); - room.addInventory(inventory); - return inventory; + private static Inventory getInventory(LocalDate date, int quantity) { + return new Inventory(date, quantity); } } diff --git a/app/src/test/java/com/hotelJava/room/domain/RoomTest.java b/app/src/test/java/com/hotelJava/room/domain/RoomTest.java new file mode 100644 index 0000000..4b609c2 --- /dev/null +++ b/app/src/test/java/com/hotelJava/room/domain/RoomTest.java @@ -0,0 +1,67 @@ +package com.hotelJava.room.domain; + +import static java.time.LocalDate.now; +import static org.assertj.core.api.Assertions.*; + +import com.hotelJava.TestFixture; +import com.hotelJava.common.embeddable.CheckDate; +import com.hotelJava.inventory.domain.Inventory; +import java.util.LinkedList; +import java.util.List; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; + +class RoomTest { + + @Test + @DisplayName("숙박 기간(체크인, 체크아웃)에 해당하는 재고를 1씩 감소시킨다") + void 객실재고감소() { + // given + Room room = TestFixture.getRoom(10, 10, now(), 10); + CheckDate checkDate = new CheckDate(now(), 1); + + // when + LinkedList beforeReduce = new LinkedList<>(room.getInventories()); + room.reduceStock(checkDate); + + // then + assertThat((isReduceQuantitySuccessful(beforeReduce, room.getInventories()))).isTrue(); + } + + private boolean isReduceQuantitySuccessful(List i1, List i2) { + for (int i = 0; i < i1.size(); i++) { + long beforeQuantity = i2.get(i).getQuantity(); + long afterQuantity = i2.get(i).getQuantity(); + if (beforeQuantity != afterQuantity) { + return false; + } + } + return true; + } + + @Test + @DisplayName("숙박 기간(체크인, 체크아웃)에 해당하는 재고 중 수량이 0 이하인 재고가 있으면 true 를 반환한다") + void 객실품절검사_true() { + // given + int duration = 10; + Room room = TestFixture.getRoom(10, 10, now(), duration); + room.getInventories().get(duration - 1).setQuantity(0); + CheckDate checkDate = new CheckDate(now(), duration); + + // when, then + room.isStockOut(checkDate); + Assertions.assertThat(room.isStockOut(checkDate)).isTrue(); + } + + @Test + @DisplayName("숙박 기간(체크인, 체크아웃)에 해당하는 재고 중 수량이 0 이하인 재고가 없다면 false 를 반환한다") + void 객실품절검사_false() { + // given + Room room = TestFixture.getRoom(10, 10, now(), 10); + CheckDate checkDate = new CheckDate(now(), 10); + + // when, then + Assertions.assertThat(room.isStockOut(checkDate)).isFalse(); + } +} From bea9922601441279c539db649f51b83160e3cbda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Thu, 11 May 2023 00:18:01 +0900 Subject: [PATCH 17/22] =?UTF-8?q?fix:=20Reservation=20=EC=83=9D=EC=84=B1?= =?UTF-8?q?=EC=9E=90=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20validate=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EA=B3=84?= =?UTF-8?q?=EC=B8=B5=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/domain/Reservation.java | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java b/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java index b7eb730..5c26e8c 100644 --- a/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java +++ b/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java @@ -1,8 +1,6 @@ package com.hotelJava.reservation.domain; import com.hotelJava.common.embeddable.CheckDate; -import com.hotelJava.common.error.ErrorCode; -import com.hotelJava.common.error.exception.BadRequestException; import com.hotelJava.common.util.BaseTimeEntity; import com.hotelJava.member.domain.Member; import com.hotelJava.payment.domain.Payment; @@ -56,8 +54,10 @@ public class Reservation extends BaseTimeEntity implements GuestInfo { @JoinColumn(name = "room_id") private Room room; - public Reservation(Member member, GuestInfo guestInfo) { + public Reservation(Member member, Room room, String reservationNo, GuestInfo guestInfo) { this.member = member; + this.room = room; + this.reservationNo = reservationNo; this.checkDate = guestInfo.getCheckDate(); this.name = guestInfo.getName(); this.numberOfGuests = guestInfo.getNumberOfGuests(); @@ -66,22 +66,9 @@ public Reservation(Member member, GuestInfo guestInfo) { } public Reservation confirm(PaymentResult paymentResult) { - validateReservation(); payment.approve(paymentResult); room.reduceStock(checkDate); status = ReservationStatus.RESERVATION_COMPLETED; return this; } - - private void validateReservation() { - if (room.isStockOut(checkDate)) { - log.info("room stock is not enough. payment declined"); - throw new BadRequestException(ErrorCode.PAYMENT_FAIL); - } - - if (!room.isLowerMaxOccupancy(numberOfGuests)) { - log.info("guest number is over max occupancy. payment declined"); - throw new BadRequestException(ErrorCode.PAYMENT_FAIL); - } - } } From ded6691f6f3543df812baf89f20efa36ebe1fa98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Fri, 12 May 2023 02:54:37 +0900 Subject: [PATCH 18/22] =?UTF-8?q?fix:=20CreateReservationRequestDto=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20GuestInfo=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/hotelJava/reservation/domain/GuestInfo.java | 4 ++-- .../reservation/dto/CreateReservationRequestDto.java | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java b/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java index a5fe66d..d401741 100644 --- a/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java +++ b/app/src/main/java/com/hotelJava/reservation/domain/GuestInfo.java @@ -4,9 +4,9 @@ public interface GuestInfo { - String getName(); + String getGuestName(); - String getPhone(); + String getGuestPhone(); int getNumberOfGuests(); diff --git a/app/src/main/java/com/hotelJava/reservation/dto/CreateReservationRequestDto.java b/app/src/main/java/com/hotelJava/reservation/dto/CreateReservationRequestDto.java index 4e27ebf..4d52ab1 100644 --- a/app/src/main/java/com/hotelJava/reservation/dto/CreateReservationRequestDto.java +++ b/app/src/main/java/com/hotelJava/reservation/dto/CreateReservationRequestDto.java @@ -2,11 +2,13 @@ import com.hotelJava.common.embeddable.CheckDate; import com.hotelJava.payment.dto.CreatePaymentRequestDto; +import com.hotelJava.reservation.domain.GuestInfo; import com.hotelJava.reservation.domain.ReservationCommand; import jakarta.validation.constraints.Future; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Positive; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Builder; @@ -17,16 +19,19 @@ @Builder @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor -public class CreateReservationRequestDto { +public class CreateReservationRequestDto implements GuestInfo { private ReservationCommand reservationCommand; @NotBlank(message = "예약자 이름을 입력해주세요.") - private String name; + private String guestName; @NotBlank(message = "휴대폰 번호의 형식이 맞지 않습니다.") @Pattern(regexp = "\\d{3}-\\d{4}-\\d{4}") - private String phoneNumber; + private String guestPhone; + + @Positive(message = "1명 이상의 인원을 입력해주세요.") + private int numberOfGuests; @NotNull(message = "체크인, 체크아웃 시간을 선택해주세요.") @Future From 458f0011f406d547b52576a9b63ca896ea069396 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Fri, 12 May 2023 02:55:08 +0900 Subject: [PATCH 19/22] =?UTF-8?q?feat:=20=EA=B0=9D=EC=8B=A4,=EC=98=88?= =?UTF-8?q?=EC=95=BD,=EA=B2=B0=EC=A0=9C=20=EA=B4=80=EB=A0=A8=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=EC=BD=94=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/src/main/java/com/hotelJava/common/error/ErrorCode.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/com/hotelJava/common/error/ErrorCode.java b/app/src/main/java/com/hotelJava/common/error/ErrorCode.java index 0330d98..9aa8751 100644 --- a/app/src/main/java/com/hotelJava/common/error/ErrorCode.java +++ b/app/src/main/java/com/hotelJava/common/error/ErrorCode.java @@ -25,12 +25,17 @@ 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, "요청값이 잘못되었습니다"), From 07707fd3da924a8c191dfdce46de4967f812f407 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Fri, 12 May 2023 02:59:52 +0900 Subject: [PATCH 20/22] =?UTF-8?q?feat:=20Payment=20=ED=94=BC=EB=93=9C?= =?UTF-8?q?=EB=B0=B1=20=EB=B0=98=EC=98=81=20+=20=EA=B2=B0=EC=A0=9C?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=EC=B4=88=EA=B3=BC=20=EA=B2=80=EC=82=AC=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 결제승인 기능 PaymentResult 반환하도록 수정 - 결제시간초과 여부 확인 기능 추가 --- .../com/hotelJava/payment/domain/Payment.java | 20 +++++++++++-------- .../payment/domain/PaymentStatus.java | 3 ++- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/hotelJava/payment/domain/Payment.java b/app/src/main/java/com/hotelJava/payment/domain/Payment.java index 25f491c..5be3834 100644 --- a/app/src/main/java/com/hotelJava/payment/domain/Payment.java +++ b/app/src/main/java/com/hotelJava/payment/domain/Payment.java @@ -1,14 +1,14 @@ package com.hotelJava.payment.domain; -import com.hotelJava.common.error.ErrorCode; -import com.hotelJava.common.error.exception.BadRequestException; 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; @@ -41,19 +41,23 @@ public class Payment { @Default private PaymentStatus status = PaymentStatus.WAITING; - @OneToOne(mappedBy = "payment") + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "reservation_id") private Reservation reservation; public Payment(int amount) { this.amount = amount; } - public void approve(PaymentResult paymentResult) { + public PaymentStatus approve(PaymentResult paymentResult) { if (paymentResult.isPayed(amount)) { - status = PaymentStatus.COMPLETE; - } else { - status = PaymentStatus.ERROR; - throw new BadRequestException(ErrorCode.PAYMENT_FAIL); + return status = PaymentStatus.COMPLETE; } + log.info("payment fail"); + return status = PaymentStatus.ERROR; + } + + public boolean isExpired() { + return status != PaymentStatus.WAITING; } } diff --git a/app/src/main/java/com/hotelJava/payment/domain/PaymentStatus.java b/app/src/main/java/com/hotelJava/payment/domain/PaymentStatus.java index ffa823d..e498264 100644 --- a/app/src/main/java/com/hotelJava/payment/domain/PaymentStatus.java +++ b/app/src/main/java/com/hotelJava/payment/domain/PaymentStatus.java @@ -4,7 +4,8 @@ public enum PaymentStatus { WAITING("결제대기"), COMPLETE("결제완료"), CANCEL("결제취소"), - ERROR("결제오류"); + ERROR("결제오류"), + TIMEOUT("결제시간초과"); private final String label; From 50b682ecbe0f71469cab64e114a18acbeaa72263 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Fri, 12 May 2023 03:12:00 +0900 Subject: [PATCH 21/22] =?UTF-8?q?feat:=20=EC=9E=AC=EA=B3=A0=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20->=20=EB=A7=A4=EA=B0=9C?= =?UTF-8?q?=EB=B3=80=EC=88=98=EB=A5=BC=20=EB=B0=9B=EC=95=84=EC=84=9C=20?= =?UTF-8?q?=ED=95=B4=EB=8B=B9=20=EA=B0=92=EB=A7=8C=ED=81=BC=20=EB=8D=94?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../reservation/domain/Reservation.java | 42 +++++++++++++++---- .../java/com/hotelJava/room/domain/Room.java | 10 ++--- 2 files changed, 40 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java b/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java index 5c26e8c..070e0bc 100644 --- a/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java +++ b/app/src/main/java/com/hotelJava/reservation/domain/Reservation.java @@ -38,12 +38,11 @@ public class Reservation extends BaseTimeEntity implements GuestInfo { private int numberOfGuests; - private String name; + private String guestName; - private String phone; + private String guestPhone; - @OneToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "payment_id") + @OneToOne(fetch = FetchType.LAZY, mappedBy = "reservation", cascade = CascadeType.ALL) private Payment payment; @ManyToOne(fetch = FetchType.LAZY) @@ -59,16 +58,45 @@ public Reservation(Member member, Room room, String reservationNo, GuestInfo gue this.room = room; this.reservationNo = reservationNo; this.checkDate = guestInfo.getCheckDate(); - this.name = guestInfo.getName(); + this.guestName = guestInfo.getGuestName(); + this.guestPhone = guestInfo.getGuestPhone(); this.numberOfGuests = guestInfo.getNumberOfGuests(); - this.phone = guestInfo.getPhone(); this.payment = new Payment(room.calcPrice()); } public Reservation confirm(PaymentResult paymentResult) { payment.approve(paymentResult); - room.reduceStock(checkDate); 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; + } } diff --git a/app/src/main/java/com/hotelJava/room/domain/Room.java b/app/src/main/java/com/hotelJava/room/domain/Room.java index ef1f44a..8f758de 100644 --- a/app/src/main/java/com/hotelJava/room/domain/Room.java +++ b/app/src/main/java/com/hotelJava/room/domain/Room.java @@ -58,20 +58,20 @@ public class Room extends BaseTimeEntity { @Builder.Default private List inventories = new ArrayList<>(); - public void reduceStock(CheckDate checkDate) { + public void calcInventory(CheckDate checkDate, int value) { inventories.stream() .filter(i -> checkDate.matches(i.getDate())) - .forEach(Inventory::reduceQuantity); + .forEach(i -> i.plusQuantity(value)); } - public boolean isStockOut(CheckDate checkDate) { + public boolean isNotEnoughInventoryAtCheckDate(CheckDate checkDate) { return inventories.stream() .filter(i -> checkDate.matches(i.getDate())) .anyMatch(Inventory::isZeroQuantity); } - public boolean isLowerMaxOccupancy(int guestNumber) { - return guestNumber <= maxOccupancy; + public boolean isOverMaxOccupancy(int guestNumber) { + return guestNumber > maxOccupancy; } public int calcPrice() { From 722f7f38bf748fc67bd2b8a93e87397aade5c254 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=ED=98=B8=EC=A4=80?= Date: Fri, 12 May 2023 03:39:17 +0900 Subject: [PATCH 22/22] =?UTF-8?q?feat:=20=EC=9E=AC=EA=B3=A0=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=20=EA=B8=B0=EB=8A=A5=20->=20=EB=A7=A4=EA=B0=9C?= =?UTF-8?q?=EB=B3=80=EC=88=98=EB=A5=BC=20=EB=B0=9B=EC=95=84=EC=84=9C=20?= =?UTF-8?q?=ED=95=B4=EB=8B=B9=20=EA=B0=92=EB=A7=8C=ED=81=BC=20=EB=8D=94?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../hotelJava/inventory/domain/Inventory.java | 4 +-- .../java/com/hotelJava/room/domain/Room.java | 2 +- .../com/hotelJava/room/domain/RoomTest.java | 29 ++++++------------- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/com/hotelJava/inventory/domain/Inventory.java b/app/src/main/java/com/hotelJava/inventory/domain/Inventory.java index b21e2c9..79e760a 100644 --- a/app/src/main/java/com/hotelJava/inventory/domain/Inventory.java +++ b/app/src/main/java/com/hotelJava/inventory/domain/Inventory.java @@ -51,7 +51,7 @@ public boolean isZeroQuantity() { return false; } - public void reduceQuantity() { - quantity--; + public void calcQuantity(int value) { + quantity += value; } } diff --git a/app/src/main/java/com/hotelJava/room/domain/Room.java b/app/src/main/java/com/hotelJava/room/domain/Room.java index 8f758de..7c7d06f 100644 --- a/app/src/main/java/com/hotelJava/room/domain/Room.java +++ b/app/src/main/java/com/hotelJava/room/domain/Room.java @@ -61,7 +61,7 @@ public class Room extends BaseTimeEntity { public void calcInventory(CheckDate checkDate, int value) { inventories.stream() .filter(i -> checkDate.matches(i.getDate())) - .forEach(i -> i.plusQuantity(value)); + .forEach(i -> i.calcQuantity(value)); } public boolean isNotEnoughInventoryAtCheckDate(CheckDate checkDate) { diff --git a/app/src/test/java/com/hotelJava/room/domain/RoomTest.java b/app/src/test/java/com/hotelJava/room/domain/RoomTest.java index 4b609c2..e88539f 100644 --- a/app/src/test/java/com/hotelJava/room/domain/RoomTest.java +++ b/app/src/test/java/com/hotelJava/room/domain/RoomTest.java @@ -5,9 +5,6 @@ import com.hotelJava.TestFixture; import com.hotelJava.common.embeddable.CheckDate; -import com.hotelJava.inventory.domain.Inventory; -import java.util.LinkedList; -import java.util.List; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -22,22 +19,14 @@ class RoomTest { CheckDate checkDate = new CheckDate(now(), 1); // when - LinkedList beforeReduce = new LinkedList<>(room.getInventories()); - room.reduceStock(checkDate); + room.calcInventory(checkDate, -1); // then - assertThat((isReduceQuantitySuccessful(beforeReduce, room.getInventories()))).isTrue(); - } - - private boolean isReduceQuantitySuccessful(List i1, List i2) { - for (int i = 0; i < i1.size(); i++) { - long beforeQuantity = i2.get(i).getQuantity(); - long afterQuantity = i2.get(i).getQuantity(); - if (beforeQuantity != afterQuantity) { - return false; - } - } - return true; + assertThat( + room.getInventories().stream() + .filter(i -> checkDate.matches(i.getDate())) + .allMatch(i -> i.getQuantity() == 9)) + .isTrue(); } @Test @@ -50,8 +39,8 @@ private boolean isReduceQuantitySuccessful(List i1, List i CheckDate checkDate = new CheckDate(now(), duration); // when, then - room.isStockOut(checkDate); - Assertions.assertThat(room.isStockOut(checkDate)).isTrue(); + room.isNotEnoughInventoryAtCheckDate(checkDate); + Assertions.assertThat(room.isNotEnoughInventoryAtCheckDate(checkDate)).isTrue(); } @Test @@ -62,6 +51,6 @@ private boolean isReduceQuantitySuccessful(List i1, List i CheckDate checkDate = new CheckDate(now(), 10); // when, then - Assertions.assertThat(room.isStockOut(checkDate)).isFalse(); + Assertions.assertThat(room.isNotEnoughInventoryAtCheckDate(checkDate)).isFalse(); } }