From 3243c936c7bec4f0c2b0fcc083dd9a7f37163642 Mon Sep 17 00:00:00 2001 From: pricelees Date: Sun, 7 Sep 2025 21:30:20 +0900 Subject: [PATCH] =?UTF-8?q?delete:=20Payment=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20=EC=99=84=EB=A3=8C=EB=A1=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=95=9C=20=EA=B8=B0=EC=A1=B4=20=EC=BD=94=EB=93=9C=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/implement/PaymentFinder.kt | 48 ----- .../payment/implement/PaymentFinderV2.kt | 53 ------ .../payment/implement/PaymentRequester.kt | 21 --- .../payment/implement/PaymentWriter.kt | 81 --------- .../PaymentCancelResponseDeserializer.kt | 29 --- .../client/TossPaymentClient.kt | 108 ------------ .../infrastructure/client/TossPaymentDTO.kt | 22 --- .../persistence/v2/CanceledPaymentEntityV2.kt | 24 --- .../v2/CanceledPaymentRepositoryV2.kt | 7 - .../persistence/v2/PaymentEntityV2.kt | 38 ---- .../persistence/v2/PaymentRepositoryV2.kt | 8 - .../payment/business/PaymentServiceTest.kt | 166 ------------------ .../payment/implement/PaymentFinderTest.kt | 93 ---------- .../payment/implement/PaymentWriterTest.kt | 121 ------------- .../PaymentCancelResponseDeserializerTest.kt | 34 ---- .../client/TossPaymentClientTest.kt | 146 --------------- .../CanceledPaymentRepositoryTest.kt | 39 ---- .../persistence/PaymentRepositoryTest.kt | 56 ------ 18 files changed, 1094 deletions(-) delete mode 100644 src/main/kotlin/roomescape/payment/implement/PaymentFinder.kt delete mode 100644 src/main/kotlin/roomescape/payment/implement/PaymentFinderV2.kt delete mode 100644 src/main/kotlin/roomescape/payment/implement/PaymentRequester.kt delete mode 100644 src/main/kotlin/roomescape/payment/implement/PaymentWriter.kt delete mode 100644 src/main/kotlin/roomescape/payment/infrastructure/client/PaymentCancelResponseDeserializer.kt delete mode 100644 src/main/kotlin/roomescape/payment/infrastructure/client/TossPaymentClient.kt delete mode 100644 src/main/kotlin/roomescape/payment/infrastructure/client/TossPaymentDTO.kt delete mode 100644 src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/CanceledPaymentEntityV2.kt delete mode 100644 src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/CanceledPaymentRepositoryV2.kt delete mode 100644 src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/PaymentEntityV2.kt delete mode 100644 src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/PaymentRepositoryV2.kt delete mode 100644 src/test/kotlin/roomescape/payment/business/PaymentServiceTest.kt delete mode 100644 src/test/kotlin/roomescape/payment/implement/PaymentFinderTest.kt delete mode 100644 src/test/kotlin/roomescape/payment/implement/PaymentWriterTest.kt delete mode 100644 src/test/kotlin/roomescape/payment/infrastructure/client/PaymentCancelResponseDeserializerTest.kt delete mode 100644 src/test/kotlin/roomescape/payment/infrastructure/client/TossPaymentClientTest.kt delete mode 100644 src/test/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentRepositoryTest.kt delete mode 100644 src/test/kotlin/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt diff --git a/src/main/kotlin/roomescape/payment/implement/PaymentFinder.kt b/src/main/kotlin/roomescape/payment/implement/PaymentFinder.kt deleted file mode 100644 index 84a64d17..00000000 --- a/src/main/kotlin/roomescape/payment/implement/PaymentFinder.kt +++ /dev/null @@ -1,48 +0,0 @@ -package roomescape.payment.implement - -import io.github.oshai.kotlinlogging.KLogger -import io.github.oshai.kotlinlogging.KotlinLogging -import org.springframework.stereotype.Component -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity -import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository -import roomescape.payment.infrastructure.persistence.PaymentEntity -import roomescape.payment.infrastructure.persistence.PaymentRepository - -private val log: KLogger = KotlinLogging.logger {} - -@Component -class PaymentFinder( - private val paymentRepository: PaymentRepository, - private val canceledPaymentRepository: CanceledPaymentRepository, -) { - fun existsPaymentByReservationId(reservationId: Long): Boolean { - log.debug { "[PaymentFinder.existsPaymentByReservationId] 시작: reservationId=$reservationId" } - - return paymentRepository.existsByReservationId(reservationId) - .also { log.debug { "[PaymentFinder.existsPaymentByReservationId] 완료: reservationId=$reservationId, isExist=$it" } } - } - - fun findByReservationId(reservationId: Long): PaymentEntity { - log.debug { "[PaymentFinder.findByReservationId] 시작: reservationId=$reservationId" } - - return paymentRepository.findByReservationId(reservationId) - ?.also { log.debug { "[PaymentFinder.findByReservationId] 완료: reservationId=$reservationId" } } - ?: run { - log.warn { "[PaymentFinder.findByReservationId] 실패: reservationId=$reservationId" } - throw PaymentException(PaymentErrorCode.PAYMENT_NOT_FOUND) - } - } - - fun findCanceledByKey(paymentKey: String): CanceledPaymentEntity { - log.debug { "[PaymentFinder.findCanceledByKey] 시작: paymentKey=$paymentKey" } - - return canceledPaymentRepository.findByPaymentKey(paymentKey) - ?.also { log.debug { "[PaymentFinder.findCanceledByKey] 완료: canceledPaymentId=${it.id}" } } - ?: run { - log.warn { "[PaymentFinder.findCanceledByKey] 실패: paymentKey=$paymentKey" } - throw PaymentException(PaymentErrorCode.CANCELED_PAYMENT_NOT_FOUND) - } - } -} diff --git a/src/main/kotlin/roomescape/payment/implement/PaymentFinderV2.kt b/src/main/kotlin/roomescape/payment/implement/PaymentFinderV2.kt deleted file mode 100644 index 8b2a5a7f..00000000 --- a/src/main/kotlin/roomescape/payment/implement/PaymentFinderV2.kt +++ /dev/null @@ -1,53 +0,0 @@ -package roomescape.payment.implement - -import io.github.oshai.kotlinlogging.KLogger -import io.github.oshai.kotlinlogging.KotlinLogging -import org.springframework.stereotype.Component -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.infrastructure.persistence.v2.CanceledPaymentEntityV2 -import roomescape.payment.infrastructure.persistence.v2.CanceledPaymentRepositoryV2 -import roomescape.payment.infrastructure.persistence.v2.PaymentDetailEntity -import roomescape.payment.infrastructure.persistence.v2.PaymentDetailRepository -import roomescape.payment.infrastructure.persistence.v2.PaymentEntityV2 -import roomescape.payment.infrastructure.persistence.v2.PaymentRepositoryV2 - -private val log: KLogger = KotlinLogging.logger {} - -@Component -class PaymentFinderV2( - private val paymentRepository: PaymentRepositoryV2, - private val paymentDetailRepository: PaymentDetailRepository, - private val canceledPaymentRepository: CanceledPaymentRepositoryV2 -) { - - fun findPaymentByReservationId(reservationId: Long): PaymentEntityV2 { - log.debug { "[PaymentFinderV2.findByReservationId] 시작: reservationId=$reservationId" } - - return paymentRepository.findByReservationId(reservationId)?.also { - log.debug { "[PaymentFinderV2.findByReservationId] 완료: reservationId=$reservationId, paymentId=${it.id}" } - } ?: run { - log.warn { "[PaymentFinderV2.findByReservationId] 실패: reservationId=$reservationId" } - throw PaymentException(PaymentErrorCode.PAYMENT_NOT_FOUND) - } - } - - fun findPaymentDetailByPaymentId(paymentId: Long): PaymentDetailEntity { - log.debug { "[PaymentFinderV2.findPaymentDetailByPaymentId] 시작: paymentId=$paymentId" } - - return paymentDetailRepository.findByPaymentId(paymentId)?.also { - log.debug { "[PaymentFinderV2.findPaymentDetailByPaymentId] 완료: paymentId=$paymentId, detailId=${it.id}" } - } ?: run { - log.warn { "[PaymentFinderV2.findPaymentDetailByPaymentId] 실패: paymentId=$paymentId" } - throw PaymentException(PaymentErrorCode.PAYMENT_DETAIL_NOT_FOUND) - } - } - - fun findCanceledPaymentByPaymentIdOrNull(paymentId: Long): CanceledPaymentEntityV2? { - log.debug { "[PaymentFinderV2.findCanceledPaymentByKey] 시작: paymentId=$paymentId" } - - return canceledPaymentRepository.findByPaymentId(paymentId)?.also { - log.debug { "[PaymentFinderV2.findCanceledPaymentByKey] 완료: paymentId=$paymentId, canceledPaymentId=${it.id}" } - } - } -} diff --git a/src/main/kotlin/roomescape/payment/implement/PaymentRequester.kt b/src/main/kotlin/roomescape/payment/implement/PaymentRequester.kt deleted file mode 100644 index bb34a34a..00000000 --- a/src/main/kotlin/roomescape/payment/implement/PaymentRequester.kt +++ /dev/null @@ -1,21 +0,0 @@ -package roomescape.payment.implement - -import org.springframework.stereotype.Component -import roomescape.payment.infrastructure.client.v2.* - -@Component -class PaymentRequester( - private val client: TosspaymentClientV2 -) { - fun requestConfirmPayment(paymentKey: String, orderId: String, amount: Int): PaymentConfirmResponse { - val request = PaymentConfirmRequest(paymentKey, orderId, amount) - - return client.confirm(request) - } - - fun requestCancelPayment(paymentKey: String, amount: Int, cancelReason: String): PaymentCancelResponseV2 { - val request = PaymentCancelRequestV2(paymentKey, amount, cancelReason) - - return client.cancel(request) - } -} diff --git a/src/main/kotlin/roomescape/payment/implement/PaymentWriter.kt b/src/main/kotlin/roomescape/payment/implement/PaymentWriter.kt deleted file mode 100644 index be815940..00000000 --- a/src/main/kotlin/roomescape/payment/implement/PaymentWriter.kt +++ /dev/null @@ -1,81 +0,0 @@ -package roomescape.payment.implement - -import com.github.f4b6a3.tsid.TsidFactory -import io.github.oshai.kotlinlogging.KLogger -import io.github.oshai.kotlinlogging.KotlinLogging -import org.springframework.stereotype.Component -import roomescape.common.config.next -import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity -import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository -import roomescape.payment.infrastructure.persistence.PaymentEntity -import roomescape.payment.infrastructure.persistence.PaymentRepository -import roomescape.reservation.infrastructure.persistence.ReservationEntity -import java.time.OffsetDateTime - -private val log: KLogger = KotlinLogging.logger {} - -@Component -class PaymentWriter( - private val paymentRepository: PaymentRepository, - private val canceledPaymentRepository: CanceledPaymentRepository, - private val tsidFactory: TsidFactory, -) { - fun create( - paymentKey: String, - orderId: String, - totalAmount: Long, - approvedAt: OffsetDateTime, - reservation: ReservationEntity - ): PaymentEntity { - log.debug { "[PaymentWriter.create] 시작: paymentKey=${paymentKey}, reservationId=${reservation.id}" } - - val payment = PaymentEntity( - _id = tsidFactory.next(), - orderId = orderId, - paymentKey = paymentKey, - totalAmount = totalAmount, - reservation = reservation, - approvedAt = approvedAt - ) - - return paymentRepository.save(payment) - .also { log.debug { "[PaymentWriter.create] 완료: paymentId=${it.id}, reservationId=${reservation.id}" } } - } - - fun createCanceled( - payment: PaymentEntity, - cancelReason: String, - canceledAt: OffsetDateTime, - ): CanceledPaymentEntity = createCanceled( - cancelReason = cancelReason, - canceledAt = canceledAt, - cancelAmount = payment.totalAmount, - approvedAt = payment.approvedAt, - paymentKey = payment.paymentKey - ) - - fun createCanceled( - cancelReason: String, - cancelAmount: Long, - canceledAt: OffsetDateTime, - approvedAt: OffsetDateTime, - paymentKey: String, - ): CanceledPaymentEntity { - log.debug { "[PaymentWriter.createCanceled] 시작: paymentKey=$paymentKey cancelAmount=$cancelAmount" } - - val canceledPayment = CanceledPaymentEntity( - _id = tsidFactory.next(), - paymentKey = paymentKey, - cancelReason = cancelReason, - cancelAmount = cancelAmount, - approvedAt = approvedAt, - canceledAt = canceledAt - ) - - return canceledPaymentRepository.save(canceledPayment) - .also { - paymentRepository.deleteByPaymentKey(paymentKey) - log.debug { "[PaymentWriter.createCanceled] 완료: paymentKey=${paymentKey}, canceledPaymentId=${it.id}" } - } - } -} diff --git a/src/main/kotlin/roomescape/payment/infrastructure/client/PaymentCancelResponseDeserializer.kt b/src/main/kotlin/roomescape/payment/infrastructure/client/PaymentCancelResponseDeserializer.kt deleted file mode 100644 index 3dc16b95..00000000 --- a/src/main/kotlin/roomescape/payment/infrastructure/client/PaymentCancelResponseDeserializer.kt +++ /dev/null @@ -1,29 +0,0 @@ -package roomescape.payment.infrastructure.client - -import com.fasterxml.jackson.core.JsonParser -import com.fasterxml.jackson.core.TreeNode -import com.fasterxml.jackson.databind.DeserializationContext -import com.fasterxml.jackson.databind.JsonNode -import com.fasterxml.jackson.databind.deser.std.StdDeserializer -import roomescape.payment.web.PaymentCancelResponse -import java.time.OffsetDateTime - -class PaymentCancelResponseDeserializer( - vc: Class? = null -) : StdDeserializer(vc) { - override fun deserialize( - jsonParser: JsonParser, - deserializationContext: DeserializationContext? - ): PaymentCancelResponse { - val cancels: JsonNode = jsonParser.codec.readTree(jsonParser) - .get("cancels") - .get(0) as JsonNode - - return PaymentCancelResponse( - cancels.get("cancelStatus").asText(), - cancels.get("cancelReason").asText(), - cancels.get("cancelAmount").asLong(), - OffsetDateTime.parse(cancels.get("canceledAt").asText()) - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/roomescape/payment/infrastructure/client/TossPaymentClient.kt b/src/main/kotlin/roomescape/payment/infrastructure/client/TossPaymentClient.kt deleted file mode 100644 index ae56e451..00000000 --- a/src/main/kotlin/roomescape/payment/infrastructure/client/TossPaymentClient.kt +++ /dev/null @@ -1,108 +0,0 @@ -package roomescape.payment.infrastructure.client - -import com.fasterxml.jackson.databind.ObjectMapper -import io.github.oshai.kotlinlogging.KLogger -import io.github.oshai.kotlinlogging.KotlinLogging -import org.springframework.http.HttpRequest -import org.springframework.http.HttpStatusCode -import org.springframework.http.MediaType -import org.springframework.http.client.ClientHttpResponse -import org.springframework.stereotype.Component -import org.springframework.web.client.RestClient -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.web.PaymentCancelRequest -import roomescape.payment.web.PaymentCancelResponse -import java.util.Map - -private val log: KLogger = KotlinLogging.logger {} - -@Component -class TossPaymentClient( - private val objectMapper: ObjectMapper, - tossPaymentClientBuilder: RestClient.Builder, -) { - companion object { - private const val CONFIRM_URL: String = "/v1/payments/confirm" - private const val CANCEL_URL: String = "/v1/payments/{paymentKey}/cancel" - } - - private val tossPaymentClient: RestClient = tossPaymentClientBuilder.build() - - fun confirm(paymentRequest: PaymentApproveRequest): PaymentApproveResponse { - logPaymentInfo(paymentRequest) - - return tossPaymentClient.post() - .uri(CONFIRM_URL) - .contentType(MediaType.APPLICATION_JSON) - .body(paymentRequest) - .retrieve() - .onStatus( - { status: HttpStatusCode -> status.is4xxClientError || status.is5xxServerError }, - { req: HttpRequest, res: ClientHttpResponse -> handlePaymentError(res, "confirm") } - ) - .body(PaymentApproveResponse::class.java) - ?: run { - log.error { "[TossPaymentClient] 응답 변환 오류" } - throw PaymentException(PaymentErrorCode.PAYMENT_PROVIDER_ERROR) - } - } - - fun cancel(cancelRequest: PaymentCancelRequest): PaymentCancelResponse { - logPaymentCancelInfo(cancelRequest) - val param = Map.of("cancelReason", cancelRequest.cancelReason) - - return tossPaymentClient.post() - .uri(CANCEL_URL, cancelRequest.paymentKey) - .contentType(MediaType.APPLICATION_JSON) - .body(param) - .retrieve() - .onStatus( - { status: HttpStatusCode -> status.is4xxClientError || status.is5xxServerError }, - { req: HttpRequest, res: ClientHttpResponse -> handlePaymentError(res, "cancel") } - ) - .body(PaymentCancelResponse::class.java) - ?: run { - log.error { "[TossPaymentClient] 응답 변환 오류" } - throw PaymentException(PaymentErrorCode.PAYMENT_PROVIDER_ERROR) - } - } - - private fun logPaymentInfo(paymentRequest: PaymentApproveRequest) { - log.info { - "[TossPaymentClient.confirm] 결제 승인 요청: request: $paymentRequest" - } - } - - private fun logPaymentCancelInfo(cancelRequest: PaymentCancelRequest) { - log.info { - "[TossPaymentClient.cancel] 결제 취소 요청: request: $cancelRequest" - } - } - - private fun handlePaymentError( - res: ClientHttpResponse, - calledBy: String - ): Nothing { - getErrorCodeByHttpStatus(res.statusCode).also { - logTossPaymentError(res, calledBy) - throw PaymentException(it) - } - } - - private fun logTossPaymentError(res: ClientHttpResponse, calledBy: String): TossPaymentErrorResponse { - val body = res.body - val errorResponse = objectMapper.readValue(body, TossPaymentErrorResponse::class.java) - body.close() - - log.error { "[TossPaymentClient.$calledBy] 요청 실패: response: $errorResponse" } - return errorResponse - } - - private fun getErrorCodeByHttpStatus(statusCode: HttpStatusCode): PaymentErrorCode { - if (statusCode.is4xxClientError) { - return PaymentErrorCode.PAYMENT_CLIENT_ERROR - } - return PaymentErrorCode.PAYMENT_PROVIDER_ERROR - } -} diff --git a/src/main/kotlin/roomescape/payment/infrastructure/client/TossPaymentDTO.kt b/src/main/kotlin/roomescape/payment/infrastructure/client/TossPaymentDTO.kt deleted file mode 100644 index 442bcf98..00000000 --- a/src/main/kotlin/roomescape/payment/infrastructure/client/TossPaymentDTO.kt +++ /dev/null @@ -1,22 +0,0 @@ -package roomescape.payment.infrastructure.client - -import java.time.OffsetDateTime - -data class TossPaymentErrorResponse( - val code: String, - val message: String -) - -data class PaymentApproveRequest( - val paymentKey: String, - val orderId: String, - val amount: Long, - val paymentType: String -) - -data class PaymentApproveResponse( - val paymentKey: String, - val orderId: String, - val totalAmount: Long, - val approvedAt: OffsetDateTime -) diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/CanceledPaymentEntityV2.kt b/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/CanceledPaymentEntityV2.kt deleted file mode 100644 index 3c7bc1a6..00000000 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/CanceledPaymentEntityV2.kt +++ /dev/null @@ -1,24 +0,0 @@ -package roomescape.payment.infrastructure.persistence.v2 - -import jakarta.persistence.Entity -import jakarta.persistence.Table -import roomescape.common.entity.PersistableBaseEntity -import java.time.LocalDateTime -import java.time.OffsetDateTime - -@Entity -@Table(name = "canceled_payment1") -class CanceledPaymentEntityV2( - id: Long, - - val paymentId: Long, - val requestedAt: LocalDateTime, - val canceledAt: OffsetDateTime, - val canceledBy: Long, - val cancelReason: String, - val cancelAmount: Int, - val cardDiscountAmount: Int, - val transferDiscountAmount: Int, - val easypayDiscountAmount: Int, -) : PersistableBaseEntity(id) - diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/CanceledPaymentRepositoryV2.kt b/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/CanceledPaymentRepositoryV2.kt deleted file mode 100644 index 59814c7e..00000000 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/CanceledPaymentRepositoryV2.kt +++ /dev/null @@ -1,7 +0,0 @@ -package roomescape.payment.infrastructure.persistence.v2 - -import org.springframework.data.jpa.repository.JpaRepository - -interface CanceledPaymentRepositoryV2 : JpaRepository { - fun findByPaymentId(paymentId: Long): CanceledPaymentEntityV2? -} diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/PaymentEntityV2.kt b/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/PaymentEntityV2.kt deleted file mode 100644 index 2d9e18cc..00000000 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/PaymentEntityV2.kt +++ /dev/null @@ -1,38 +0,0 @@ -package roomescape.payment.infrastructure.persistence.v2 - -import jakarta.persistence.Entity -import jakarta.persistence.EnumType -import jakarta.persistence.Enumerated -import jakarta.persistence.Table -import roomescape.common.entity.PersistableBaseEntity -import roomescape.payment.infrastructure.common.PaymentMethod -import roomescape.payment.infrastructure.common.PaymentStatus -import roomescape.payment.infrastructure.common.PaymentType -import java.time.OffsetDateTime - -@Entity -@Table(name = "payment1") -class PaymentEntityV2( - id: Long, - - val reservationId: Long, - val paymentKey: String, - val orderId: String, - val totalAmount: Int, - val requestedAt: OffsetDateTime, - val approvedAt: OffsetDateTime, - - @Enumerated(EnumType.STRING) - val type: PaymentType, - - @Enumerated(EnumType.STRING) - val method: PaymentMethod, - - @Enumerated(EnumType.STRING) - var status: PaymentStatus -) : PersistableBaseEntity(id) { - - fun cancel() { - this.status = PaymentStatus.CANCELED - } -} diff --git a/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/PaymentRepositoryV2.kt b/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/PaymentRepositoryV2.kt deleted file mode 100644 index 6fd16b94..00000000 --- a/src/main/kotlin/roomescape/payment/infrastructure/persistence/v2/PaymentRepositoryV2.kt +++ /dev/null @@ -1,8 +0,0 @@ -package roomescape.payment.infrastructure.persistence.v2 - -import org.springframework.data.jpa.repository.JpaRepository - -interface PaymentRepositoryV2: JpaRepository { - - fun findByReservationId(reservationId: Long): PaymentEntityV2? -} diff --git a/src/test/kotlin/roomescape/payment/business/PaymentServiceTest.kt b/src/test/kotlin/roomescape/payment/business/PaymentServiceTest.kt deleted file mode 100644 index 94ff5c8e..00000000 --- a/src/test/kotlin/roomescape/payment/business/PaymentServiceTest.kt +++ /dev/null @@ -1,166 +0,0 @@ -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.kotest.matchers.types.shouldBeInstanceOf -import io.mockk.every -import io.mockk.mockk -import io.mockk.slot -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.implement.PaymentFinder -import roomescape.payment.implement.PaymentWriter -import roomescape.payment.infrastructure.client.PaymentApproveResponse -import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity -import roomescape.payment.web.PaymentCancelRequest -import roomescape.payment.web.PaymentCancelResponse -import roomescape.util.PaymentFixture -import roomescape.util.ReservationFixture -import java.time.LocalDate -import java.time.LocalTime -import java.time.OffsetDateTime -import java.time.ZoneOffset - -class PaymentServiceTest : FunSpec({ - val paymentFinder: PaymentFinder = mockk() - val paymentWriter: PaymentWriter = mockk() - - val paymentService = PaymentService(paymentFinder, paymentWriter) - - context("createPayment") { - val approvedPaymentInfo = PaymentApproveResponse( - paymentKey = "paymentKey", - orderId = "orderId", - totalAmount = 1000L, - approvedAt = OffsetDateTime.now(), - ) - val reservation = ReservationFixture.create(id = 1L) - - test("정상 응답") { - every { - paymentWriter.create( - paymentKey = approvedPaymentInfo.paymentKey, - orderId = approvedPaymentInfo.orderId, - totalAmount = approvedPaymentInfo.totalAmount, - approvedAt = approvedPaymentInfo.approvedAt, - reservation = reservation - ) - } returns PaymentFixture.create( - id = 1L, - orderId = approvedPaymentInfo.orderId, - paymentKey = approvedPaymentInfo.paymentKey, - totalAmount = approvedPaymentInfo.totalAmount, - approvedAt = approvedPaymentInfo.approvedAt, - reservation = reservation - ) - - val response = paymentService.createPayment(approvedPaymentInfo, reservation) - - assertSoftly(response) { - it.id shouldBe 1L - it.paymentKey shouldBe approvedPaymentInfo.paymentKey - it.reservationId shouldBe reservation.id - } - } - } - - context("createCanceledPayment(canceledPaymentInfo)") { - val canceledPaymentInfo = PaymentCancelResponse( - cancelStatus = "normal", - cancelReason = "고객 요청", - cancelAmount = 1000L, - canceledAt = OffsetDateTime.now(), - ) - val approvedAt = OffsetDateTime.now() - val paymentKey = "paymentKey" - - test("CanceledPaymentEntity를 응답") { - every { - paymentWriter.createCanceled( - cancelReason = canceledPaymentInfo.cancelReason, - cancelAmount = canceledPaymentInfo.cancelAmount, - canceledAt = canceledPaymentInfo.canceledAt, - approvedAt = approvedAt, - paymentKey = paymentKey - ) - } returns PaymentFixture.createCanceled( - id = 1L, - paymentKey = paymentKey, - cancelAmount = canceledPaymentInfo.cancelAmount - ) - - val response = paymentService.createCanceledPayment(canceledPaymentInfo, approvedAt, paymentKey) - - response.shouldBeInstanceOf() - response.paymentKey shouldBe paymentKey - } - } - - context("createCanceledPayment(reservationId)") { - val reservationId = 1L - - test("취소 사유를 '예약 취소'로 하여 PaymentCancelRequest를 응답") { - val payment = PaymentFixture.create(id = 1L, paymentKey = "paymentKey", totalAmount = 1000L) - every { - paymentFinder.findByReservationId(reservationId) - } returns payment - - val cancelReasonSlot = slot() - - every { - paymentWriter.createCanceled(payment, capture(cancelReasonSlot), any()) - } returns PaymentFixture.createCanceled( - id = 1L, - paymentKey = payment.paymentKey, - cancelAmount = payment.totalAmount - ) - - val response = paymentService.createCanceledPayment(reservationId) - - response.shouldBeInstanceOf() - cancelReasonSlot.captured shouldBe "예약 취소" - } - - test("결제 정보가 없으면 예외 응답") { - every { - paymentFinder.findByReservationId(reservationId) - } throws PaymentException(PaymentErrorCode.PAYMENT_NOT_FOUND) - - shouldThrow { - paymentService.createCanceledPayment(reservationId) - }.also { - it.errorCode shouldBe PaymentErrorCode.PAYMENT_NOT_FOUND - } - } - } - - context("updateCanceledTime") { - val paymentKey = "paymentKey" - val canceledAt = OffsetDateTime.of(LocalDate.of(2025, 8, 5), LocalTime.of(10, 0), ZoneOffset.UTC) - - test("정상 응답") { - val canceled = PaymentFixture.createCanceled(id = 1L) - every { - paymentFinder.findCanceledByKey(paymentKey) - } returns canceled - - paymentService.updateCanceledTime(paymentKey, canceledAt) - - canceled.canceledAt shouldBe canceledAt - } - - test("결제 취소 정보가 없으면 예외 응답") { - every { - paymentFinder.findCanceledByKey(paymentKey) - } throws PaymentException(PaymentErrorCode.PAYMENT_NOT_FOUND) - - shouldThrow { - paymentService.updateCanceledTime(paymentKey, canceledAt) - }.also { - it.errorCode shouldBe PaymentErrorCode.PAYMENT_NOT_FOUND - } - } - } -}) diff --git a/src/test/kotlin/roomescape/payment/implement/PaymentFinderTest.kt b/src/test/kotlin/roomescape/payment/implement/PaymentFinderTest.kt deleted file mode 100644 index b5fd6d10..00000000 --- a/src/test/kotlin/roomescape/payment/implement/PaymentFinderTest.kt +++ /dev/null @@ -1,93 +0,0 @@ -package roomescape.payment.implement - -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.mockk -import io.mockk.verify -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository -import roomescape.payment.infrastructure.persistence.PaymentRepository - -class PaymentFinderTest : FunSpec({ - val paymentRepository: PaymentRepository = mockk() - val canceledPaymentRepository: CanceledPaymentRepository = mockk() - - val paymentFinder = PaymentFinder(paymentRepository, canceledPaymentRepository) - - context("existsPaymentByReservationId") { - val reservationId = 1L - test("결제 정보가 있으면 true를 반환한다.") { - every { - paymentRepository.existsByReservationId(reservationId) - } returns true - - paymentFinder.existsPaymentByReservationId(reservationId) shouldBe true - } - - test("결제 정보가 없으면 false를 반환한다.") { - every { - paymentRepository.existsByReservationId(reservationId) - } returns false - - paymentFinder.existsPaymentByReservationId(reservationId) shouldBe false - } - } - - context("findByReservationId") { - val reservationId = 1L - test("결제 정보를 조회한다.") { - every { - paymentRepository.findByReservationId(reservationId) - } returns mockk() - - paymentFinder.findByReservationId(reservationId) - - verify(exactly = 1) { - paymentRepository.findByReservationId(reservationId) - } - } - - test("결제 정보가 없으면 실패한다.") { - every { - paymentRepository.findByReservationId(reservationId) - } returns null - - shouldThrow { - paymentFinder.findByReservationId(reservationId) - }.also { - it.errorCode shouldBe PaymentErrorCode.PAYMENT_NOT_FOUND - } - } - } - - context("findCanceledByKey") { - val paymentKey = "paymentKey" - - test("결제 취소 정보를 조회한다.") { - every { - canceledPaymentRepository.findByPaymentKey(paymentKey) - } returns mockk() - - paymentFinder.findCanceledByKey(paymentKey) - - verify(exactly = 1) { - canceledPaymentRepository.findByPaymentKey(paymentKey) - } - } - - test("결제 취소 정보가 없으면 실패한다.") { - every { - canceledPaymentRepository.findByPaymentKey(paymentKey) - } returns null - - shouldThrow { - paymentFinder.findCanceledByKey(paymentKey) - }.also { - it.errorCode shouldBe PaymentErrorCode.CANCELED_PAYMENT_NOT_FOUND - } - } - } -}) diff --git a/src/test/kotlin/roomescape/payment/implement/PaymentWriterTest.kt b/src/test/kotlin/roomescape/payment/implement/PaymentWriterTest.kt deleted file mode 100644 index ac003c06..00000000 --- a/src/test/kotlin/roomescape/payment/implement/PaymentWriterTest.kt +++ /dev/null @@ -1,121 +0,0 @@ -package roomescape.payment.implement - -import com.ninjasquad.springmockk.MockkClear -import com.ninjasquad.springmockk.clear -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.date.after -import io.kotest.matchers.shouldBe -import io.mockk.clearMocks -import io.mockk.every -import io.mockk.mockk -import io.mockk.slot -import io.mockk.verify -import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity -import roomescape.payment.infrastructure.persistence.CanceledPaymentRepository -import roomescape.payment.infrastructure.persistence.PaymentEntity -import roomescape.payment.infrastructure.persistence.PaymentRepository -import roomescape.reservation.infrastructure.persistence.ReservationEntity -import roomescape.util.PaymentFixture -import roomescape.util.ReservationFixture -import roomescape.util.TsidFactory -import java.time.OffsetDateTime - -class PaymentWriterTest : FunSpec({ - val paymentRepository: PaymentRepository = mockk() - val canceledPaymentRepository: CanceledPaymentRepository = mockk() - - val paymentWriter = PaymentWriter(paymentRepository, canceledPaymentRepository, TsidFactory) - - val paymentKey = "paymentKey" - val orderId = "orderId" - val totalAmount = 1000L - val approvedAt = OffsetDateTime.now() - - context("create") { - val reservation: ReservationEntity = ReservationFixture.create(id = 1L) - test("결제 정보를 저장한다.") { - val slot = slot() - every { - paymentRepository.save(capture(slot)) - } returns mockk() - - paymentWriter.create(paymentKey, orderId, totalAmount, approvedAt, reservation) - - verify(exactly = 1) { - paymentRepository.save(any()) - } - - slot.captured.also { - it.paymentKey shouldBe paymentKey - it.orderId shouldBe orderId - it.totalAmount shouldBe totalAmount - it.approvedAt shouldBe approvedAt - } - - paymentRepository.clear(MockkClear.AFTER) - } - } - - context("createCanceled") { - val cancelReason = "고객 요청" - val canceledAt = OffsetDateTime.now() - - afterTest { - clearMocks(paymentRepository) - clearMocks(canceledPaymentRepository) - } - - test("PaymentEntity를 받아 저장한다.") { - val payment: PaymentEntity = PaymentFixture.create(id = 1L) - val slot = slot() - - every { - canceledPaymentRepository.save(capture(slot)) - } returns mockk() - - every { - paymentRepository.deleteByPaymentKey(paymentKey) - } returns Unit - - paymentWriter.createCanceled(payment, cancelReason, canceledAt) - - verify(exactly = 1) { canceledPaymentRepository.save(any()) } - verify(exactly = 1) { paymentRepository.deleteByPaymentKey(any()) } - - slot.captured.also { - it.paymentKey shouldBe payment.paymentKey - it.cancelAmount shouldBe payment.totalAmount - it.approvedAt shouldBe payment.approvedAt - } - } - - test("취소 정보를 받아 저장한다.") { - val slot = slot() - - every { - canceledPaymentRepository.save(capture(slot)) - } returns mockk() - - every { - paymentRepository.deleteByPaymentKey(paymentKey) - } returns Unit - - paymentWriter.createCanceled( - cancelReason = cancelReason, - cancelAmount = totalAmount, - canceledAt = canceledAt, - approvedAt = approvedAt, - paymentKey = paymentKey - ) - - verify(exactly = 1) { canceledPaymentRepository.save(any()) } - verify(exactly = 1) { paymentRepository.deleteByPaymentKey(any()) } - - slot.captured.also { - it.paymentKey shouldBe paymentKey - it.cancelAmount shouldBe totalAmount - it.approvedAt shouldBe approvedAt - } - } - } -}) diff --git a/src/test/kotlin/roomescape/payment/infrastructure/client/PaymentCancelResponseDeserializerTest.kt b/src/test/kotlin/roomescape/payment/infrastructure/client/PaymentCancelResponseDeserializerTest.kt deleted file mode 100644 index eb4f74aa..00000000 --- a/src/test/kotlin/roomescape/payment/infrastructure/client/PaymentCancelResponseDeserializerTest.kt +++ /dev/null @@ -1,34 +0,0 @@ -package roomescape.payment.infrastructure.client - -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.module.SimpleModule -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import io.kotest.assertions.assertSoftly -import io.kotest.core.spec.style.StringSpec -import io.kotest.matchers.shouldBe -import roomescape.payment.web.PaymentCancelResponse - -class PaymentCancelResponseDeserializerTest : StringSpec({ - - val objectMapper: ObjectMapper = jacksonObjectMapper().registerModule( - SimpleModule().addDeserializer( - PaymentCancelResponse::class.java, - PaymentCancelResponseDeserializer() - ) - ) - - "결제 취소 응답을 역직렬화하여 PaymentCancelResponse 객체를 생성한다" { - val cancelResponseJson: String = SampleTossPaymentConst.cancelJson - val cancelResponse: PaymentCancelResponse = objectMapper.readValue( - cancelResponseJson, - PaymentCancelResponse::class.java - ) - - assertSoftly(cancelResponse) { - cancelResponse.cancelStatus shouldBe "DONE" - cancelResponse.cancelReason shouldBe SampleTossPaymentConst.cancelReason - cancelResponse.cancelAmount shouldBe SampleTossPaymentConst.amount - cancelResponse.canceledAt.toString() shouldBe "2024-02-13T12:20:23+09:00" - } - } -}) \ No newline at end of file diff --git a/src/test/kotlin/roomescape/payment/infrastructure/client/TossPaymentClientTest.kt b/src/test/kotlin/roomescape/payment/infrastructure/client/TossPaymentClientTest.kt deleted file mode 100644 index 98419344..00000000 --- a/src/test/kotlin/roomescape/payment/infrastructure/client/TossPaymentClientTest.kt +++ /dev/null @@ -1,146 +0,0 @@ -package roomescape.payment.infrastructure.client - -import com.ninjasquad.springmockk.MockkBean -import io.kotest.assertions.assertSoftly -import io.kotest.assertions.throwables.shouldThrow -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.web.client.RestClientTest -import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext -import org.springframework.http.HttpMethod -import org.springframework.http.HttpStatus -import org.springframework.http.MediaType -import org.springframework.test.web.client.MockRestServiceServer -import org.springframework.test.web.client.ResponseActions -import org.springframework.test.web.client.match.MockRestRequestMatchers.* -import org.springframework.test.web.client.response.MockRestResponseCreators.withStatus -import org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess -import roomescape.payment.exception.PaymentErrorCode -import roomescape.payment.exception.PaymentException -import roomescape.payment.web.PaymentCancelRequest -import roomescape.payment.web.PaymentCancelResponse - -@RestClientTest(TossPaymentClient::class) -@MockkBean(JpaMetamodelMappingContext::class) -class TossPaymentClientTest( - @Autowired val client: TossPaymentClient, - @Autowired val mockServer: MockRestServiceServer -) : FunSpec() { - - init { - context("결제 승인 요청") { - fun commonAction(): ResponseActions = mockServer.expect { - requestTo("/v1/payments/confirm") - }.andExpect { - method(HttpMethod.POST) - }.andExpect { - content().contentType(MediaType.APPLICATION_JSON) - }.andExpect { - content().json(SampleTossPaymentConst.paymentRequestJson) - } - - test("성공 응답") { - commonAction().andRespond { - withSuccess() - .contentType(MediaType.APPLICATION_JSON) - .body(SampleTossPaymentConst.confirmJson) - .createResponse(it) - } - - val paymentRequest = SampleTossPaymentConst.paymentRequest - val paymentResponse: PaymentApproveResponse = client.confirm(paymentRequest) - - assertSoftly(paymentResponse) { - this.paymentKey shouldBe paymentRequest.paymentKey - this.orderId shouldBe paymentRequest.orderId - this.totalAmount shouldBe paymentRequest.amount - } - } - - context("실패 응답") { - fun runTest(httpStatus: HttpStatus, expectedError: PaymentErrorCode) { - commonAction().andRespond { - withStatus(httpStatus) - .contentType(MediaType.APPLICATION_JSON) - .body(SampleTossPaymentConst.tossPaymentErrorJson) - .createResponse(it) - } - - val paymentRequest = SampleTossPaymentConst.paymentRequest - - // then - val exception = shouldThrow { - client.confirm(paymentRequest) - } - exception.errorCode shouldBe expectedError - } - - test("결제 서버에서 4XX 응답 시") { - runTest(HttpStatus.BAD_REQUEST, PaymentErrorCode.PAYMENT_CLIENT_ERROR) - } - - test("결제 서버에서 5XX 응답 시") { - runTest(HttpStatus.INTERNAL_SERVER_ERROR, PaymentErrorCode.PAYMENT_PROVIDER_ERROR) - } - } - } - - context("결제 취소 요청") { - fun commonAction(): ResponseActions = mockServer.expect { - requestTo("/v1/payments/${SampleTossPaymentConst.paymentKey}/cancel") - }.andExpect { - method(HttpMethod.POST) - }.andExpect { - content().contentType(MediaType.APPLICATION_JSON) - }.andExpect { - content().json(SampleTossPaymentConst.cancelRequestJson) - } - - test("성공 응답") { - commonAction().andRespond { - withSuccess() - .contentType(MediaType.APPLICATION_JSON) - .body(SampleTossPaymentConst.cancelJson) - .createResponse(it) - } - - - val cancelRequest: PaymentCancelRequest = SampleTossPaymentConst.cancelRequest - val cancelResponse: PaymentCancelResponse = client.cancel(cancelRequest) - - assertSoftly(cancelResponse) { - this.cancelStatus shouldBe "DONE" - this.cancelReason shouldBe cancelRequest.cancelReason - this.cancelAmount shouldBe cancelRequest.amount - } - } - - context("실패 응답") { - fun runTest(httpStatus: HttpStatus, expectedError: PaymentErrorCode) { - commonAction().andRespond { - withStatus(httpStatus) - .contentType(MediaType.APPLICATION_JSON) - .body(SampleTossPaymentConst.tossPaymentErrorJson) - .createResponse(it) - } - - val cancelRequest: PaymentCancelRequest = SampleTossPaymentConst.cancelRequest - - val exception = shouldThrow { - client.cancel(cancelRequest) - } - exception.errorCode shouldBe expectedError - } - - test("결제 서버에서 4XX 응답 시") { - runTest(HttpStatus.BAD_REQUEST, PaymentErrorCode.PAYMENT_CLIENT_ERROR) - } - - test("결제 서버에서 5XX 응답 시") { - runTest(HttpStatus.INTERNAL_SERVER_ERROR, PaymentErrorCode.PAYMENT_PROVIDER_ERROR) - } - } - } - } -} diff --git a/src/test/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentRepositoryTest.kt b/src/test/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentRepositoryTest.kt deleted file mode 100644 index 052d1eb8..00000000 --- a/src/test/kotlin/roomescape/payment/infrastructure/persistence/CanceledPaymentRepositoryTest.kt +++ /dev/null @@ -1,39 +0,0 @@ -package roomescape.payment.infrastructure.persistence - -import io.kotest.assertions.assertSoftly -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest -import roomescape.common.config.next -import roomescape.util.PaymentFixture -import roomescape.util.TsidFactory -import java.util.* - -@DataJpaTest(showSql = false) -class CanceledPaymentRepositoryTest( - @Autowired val canceledPaymentRepository: CanceledPaymentRepository, -) : FunSpec() { - init { - context("paymentKey로 CanceledPaymentEntity 조회") { - val paymentKey = "test-payment-key" - beforeTest { - PaymentFixture.createCanceled(id = TsidFactory.next(), paymentKey = paymentKey) - .also { canceledPaymentRepository.save(it) } - } - - test("정상 반환") { - canceledPaymentRepository.findByPaymentKey(paymentKey)?.let { - assertSoftly(it) { - this.paymentKey shouldBe paymentKey - } - } ?: throw AssertionError("Unexpected null value") - } - - test("null 반환") { - canceledPaymentRepository.findByPaymentKey(UUID.randomUUID().toString()) - .also { it shouldBe null } - } - } - } -} diff --git a/src/test/kotlin/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt b/src/test/kotlin/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt deleted file mode 100644 index a58d0580..00000000 --- a/src/test/kotlin/roomescape/payment/infrastructure/persistence/PaymentRepositoryTest.kt +++ /dev/null @@ -1,56 +0,0 @@ -package roomescape.payment.infrastructure.persistence - -import io.kotest.assertions.assertSoftly -import io.kotest.core.spec.style.FunSpec -import io.kotest.matchers.shouldBe -import jakarta.persistence.EntityManager -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest -import roomescape.common.config.next -import roomescape.reservation.infrastructure.persistence.ReservationEntity -import roomescape.util.PaymentFixture -import roomescape.util.ReservationFixture -import roomescape.util.TsidFactory - -@DataJpaTest(showSql = false) -class PaymentRepositoryTest( - @Autowired val paymentRepository: PaymentRepository, - @Autowired val entityManager: EntityManager -) : FunSpec() { - - lateinit var reservation: ReservationEntity - - init { - context("existsByReservationId") { - beforeTest { - reservation = setupReservation() - PaymentFixture.create(reservation = reservation) - .also { paymentRepository.save(it) } - } - - test("true") { - paymentRepository.existsByReservationId(reservation.id!!) - .also { it shouldBe true } - } - - test("false") { - paymentRepository.existsByReservationId(reservation.id!! + 1L) - .also { it shouldBe false } - } - } - } - - private fun setupReservation(): ReservationEntity { - return ReservationFixture.create( - id = TsidFactory.next() - ).also { - entityManager.persist(it.member) - entityManager.persist(it.theme) - entityManager.persist(it.time) - entityManager.persist(it) - - entityManager.flush() - entityManager.clear() - } - } -}