package roomescape.payment.business; import static org.assertj.core.api.Assertions.*; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.OffsetDateTime; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.jdbc.Sql; import org.springframework.test.context.jdbc.Sql.ExecutionPhase; import roomescape.common.exception.RoomescapeException; import roomescape.member.infrastructure.persistence.MemberEntity; import roomescape.member.infrastructure.persistence.MemberRepository; import roomescape.member.infrastructure.persistence.Role; import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity; import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository; import roomescape.payment.web.PaymentApprove; import roomescape.payment.web.PaymentCancel; import roomescape.payment.web.ReservationPaymentResponse; import roomescape.reservation.infrastructure.persistence.Reservation; import roomescape.reservation.infrastructure.persistence.ReservationRepository; import roomescape.reservation.infrastructure.persistence.ReservationStatus; import roomescape.reservation.infrastructure.persistence.ReservationTimeEntity; import roomescape.reservation.infrastructure.persistence.ReservationTimeRepository; import roomescape.theme.infrastructure.persistence.ThemeEntity; import roomescape.theme.infrastructure.persistence.ThemeRepository; @SpringBootTest @Sql(scripts = "/truncate.sql", executionPhase = ExecutionPhase.BEFORE_TEST_METHOD) class PaymentServiceTest { @Autowired private PaymentService paymentService; @Autowired private ReservationRepository reservationRepository; @Autowired private MemberRepository memberRepository; @Autowired private ReservationTimeRepository reservationTimeRepository; @Autowired private ThemeRepository themeRepository; @Autowired private CanceledPaymentRepository canceledPaymentRepository; @Test @DisplayName("결제 정보를 저장한다.") void savePayment() { // given PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); // when ReservationPaymentResponse reservationPaymentResponse = paymentService.savePayment(paymentInfo, reservation); // then assertThat(reservationPaymentResponse.reservation().id).isEqualTo(reservation.getId()); assertThat(reservationPaymentResponse.paymentKey()).isEqualTo(paymentInfo.paymentKey); } @Test @DisplayName("예약 ID로 결제 정보를 제거하고, 결제 취소 테이블에 취소 정보를 저장한다.") void cancelPaymentByAdmin() { // given PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); paymentService.savePayment(paymentInfo, reservation); // when PaymentCancel.Request paymentCancelRequest = paymentService.cancelPaymentByAdmin(reservation.getId()); // then assertThat(canceledPaymentRepository.findByPaymentKey("payment-key")).isNotNull(); assertThat(paymentCancelRequest.paymentKey).isEqualTo(paymentInfo.paymentKey); assertThat(paymentCancelRequest.cancelReason).isEqualTo("고객 요청"); assertThat(paymentCancelRequest.amount).isEqualTo(10000L); } @Test @DisplayName("입력된 예약 ID에 대한 결제 정보가 없으면 예외가 발생한다.") void cancelPaymentByAdminWithNonExistentReservationId() { // given Long nonExistentReservationId = 1L; // when assertThatThrownBy(() -> paymentService.cancelPaymentByAdmin(nonExistentReservationId)) .isInstanceOf(RoomescapeException.class); } @Test @DisplayName("결제 취소 정보에 있는 취소 시간을 업데이트한다.") void updateCanceledTime() { // given PaymentApprove.Response paymentInfo = new PaymentApprove.Response("payment-key", "order-id", OffsetDateTime.now(), 10000L); LocalDateTime localDateTime = LocalDateTime.now().plusHours(1L); LocalDate date = localDateTime.toLocalDate(); ReservationTimeEntity time = reservationTimeRepository.save(new ReservationTimeEntity(null, localDateTime.toLocalTime())); MemberEntity member = memberRepository.save( new MemberEntity(null, "member", "email@email.com", "password", Role.MEMBER)); ThemeEntity theme = themeRepository.save(new ThemeEntity(null, "name", "desc", "thumbnail")); Reservation reservation = reservationRepository.save(new Reservation(date, time, theme, member, ReservationStatus.CONFIRMED)); paymentService.savePayment(paymentInfo, reservation); paymentService.cancelPaymentByAdmin(reservation.getId()); // when OffsetDateTime canceledAt = OffsetDateTime.now().plusHours(2L); paymentService.updateCanceledTime(paymentInfo.paymentKey, canceledAt); // then CanceledPaymentEntity canceledPayment = canceledPaymentRepository.findByPaymentKey(paymentInfo.paymentKey); assertThat(canceledPayment).isNotNull(); assertThat(canceledPayment.getCanceledAt()).isEqualTo(canceledAt); } @Test @DisplayName("결제 취소 시간을 업데이트 할 때, 입력한 paymentKey가 존재하지 않으면 예외가 발생한다.") void updateCanceledTimeWithNonExistentPaymentKey() { // given OffsetDateTime canceledAt = OffsetDateTime.now().plusHours(2L); // when assertThatThrownBy(() -> paymentService.updateCanceledTime("non-existent-payment-key", canceledAt)) .isInstanceOf(RoomescapeException.class); } }