package roomescape.payment.business import io.kotest.assertions.assertSoftly import io.kotest.assertions.throwables.shouldThrow import io.kotest.core.spec.style.FunSpec import io.kotest.matchers.shouldBe import io.mockk.every import io.mockk.just import io.mockk.mockk import io.mockk.runs import org.springframework.http.HttpStatus import roomescape.common.exception.ErrorType import roomescape.common.exception.RoomescapeException import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository import roomescape.payment.infrastructure.persistence.PaymentRepository import roomescape.payment.web.PaymentCancelRequest import roomescape.util.PaymentFixture import java.time.OffsetDateTime class PaymentServiceTest : FunSpec({ val paymentRepository: PaymentRepository = mockk() val canceledPaymentRepository: CanceledPaymentRepository = mockk() val paymentService = PaymentService(paymentRepository, canceledPaymentRepository) context("cancelPaymentByAdmin") { val reservationId = 1L test("reservationId로 paymentKey를 찾을 수 없으면 예외를 던진다.") { every { paymentRepository.findPaymentKeyByReservationId(reservationId) } returns null val exception = shouldThrow { paymentService.createCanceledPaymentByReservationId(reservationId) } assertSoftly(exception) { this.errorType shouldBe ErrorType.PAYMENT_NOT_FOUND this.httpStatus shouldBe HttpStatus.NOT_FOUND } } context("reservationId로 paymentKey를 찾고난 후") { val paymentKey = "test-payment-key" every { paymentRepository.findPaymentKeyByReservationId(reservationId) } returns paymentKey test("해당 paymentKey로 paymentEntity를 찾을 수 없으면 예외를 던진다.") { every { paymentRepository.findByPaymentKey(paymentKey) } returns null val exception = shouldThrow { paymentService.createCanceledPaymentByReservationId(reservationId) } assertSoftly(exception) { this.errorType shouldBe ErrorType.PAYMENT_NOT_FOUND this.httpStatus shouldBe HttpStatus.NOT_FOUND } } test("해당 paymentKey로 paymentEntity를 찾고, cancelPaymentEntity를 저장한다.") { val paymentEntity = PaymentFixture.create(paymentKey = paymentKey) every { paymentRepository.findByPaymentKey(paymentKey) } returns paymentEntity.also { every { paymentRepository.delete(it) } just runs } every { canceledPaymentRepository.save(any()) } returns PaymentFixture.createCanceled( id = 1L, paymentKey = paymentKey, cancelAmount = paymentEntity.totalAmount, ) val result: PaymentCancelRequest = paymentService.createCanceledPaymentByReservationId(reservationId) assertSoftly(result) { this.paymentKey shouldBe paymentKey this.amount shouldBe paymentEntity.totalAmount this.cancelReason shouldBe "고객 요청" } } } } context("updateCanceledTime") { val paymentKey = "test-payment-key" val canceledAt = OffsetDateTime.now() test("paymentKey로 canceledPaymentEntity를 찾을 수 없으면 예외를 던진다.") { every { canceledPaymentRepository.findByPaymentKey(paymentKey) } returns null val exception = shouldThrow { paymentService.updateCanceledTime(paymentKey, canceledAt) } assertSoftly(exception) { this.errorType shouldBe ErrorType.PAYMENT_NOT_FOUND this.httpStatus shouldBe HttpStatus.NOT_FOUND } } test("paymentKey로 canceledPaymentEntity를 찾고, canceledAt을 업데이트한다.") { val canceledPaymentEntity = PaymentFixture.createCanceled( paymentKey = paymentKey, canceledAt = canceledAt.minusMinutes(1) ) every { canceledPaymentRepository.findByPaymentKey(paymentKey) } returns canceledPaymentEntity paymentService.updateCanceledTime(paymentKey, canceledAt) assertSoftly(canceledPaymentEntity) { this.canceledAt shouldBe canceledAt } } } })