[#56] 예약 & 결제 프로세스 및 패키지 구조 재정의 #57

Merged
pricelees merged 45 commits from refactor/#56 into main 2025-10-09 09:33:29 +00:00
3 changed files with 25 additions and 12 deletions
Showing only changes of commit 1652398fcc - Show all commits

View File

@ -6,3 +6,9 @@ class PaymentException(
override val errorCode: PaymentErrorCode, override val errorCode: PaymentErrorCode,
override val message: String = errorCode.message override val message: String = errorCode.message
) : RoomescapeException(errorCode, message) ) : RoomescapeException(errorCode, message)
class ExternalPaymentException(
val httpStatusCode: Int,
val errorCode: String,
override val message: String
) : RuntimeException(message)

View File

@ -1,6 +1,7 @@
package com.sangdol.roomescape.payment.infrastructure.client package com.sangdol.roomescape.payment.infrastructure.client
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import com.sangdol.roomescape.payment.exception.ExternalPaymentException
import com.sangdol.roomescape.payment.exception.PaymentErrorCode import com.sangdol.roomescape.payment.exception.PaymentErrorCode
import com.sangdol.roomescape.payment.exception.PaymentException import com.sangdol.roomescape.payment.exception.PaymentException
import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KLogger
@ -138,9 +139,14 @@ private class TosspayErrorHandler(
response: ClientHttpResponse response: ClientHttpResponse
): Nothing { ): Nothing {
val requestType: String = paymentRequestType(url) val requestType: String = paymentRequestType(url)
log.warn { "[TosspayClient] $requestType 요청 실패: response: ${parseResponse(response)}" } val errorResponse: TosspayErrorResponse = parseResponse(response)
log.warn { "[TosspayClient] $requestType 요청 실패: response: $errorResponse" }
throw PaymentException(paymentErrorCode(response.statusCode)) throw ExternalPaymentException(
httpStatusCode = response.statusCode.value(),
errorCode = errorResponse.code,
message = errorResponse.message
)
} }
private fun paymentRequestType(url: URI): String { private fun paymentRequestType(url: URI): String {

View File

@ -1,6 +1,7 @@
package com.sangdol.roomescape.payment package com.sangdol.roomescape.payment
import com.ninjasquad.springmockk.MockkBean import com.ninjasquad.springmockk.MockkBean
import com.sangdol.roomescape.payment.exception.ExternalPaymentException
import com.sangdol.roomescape.payment.exception.PaymentErrorCode import com.sangdol.roomescape.payment.exception.PaymentErrorCode
import com.sangdol.roomescape.payment.exception.PaymentException import com.sangdol.roomescape.payment.exception.PaymentException
import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientCancelResponse import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientCancelResponse
@ -67,7 +68,7 @@ class TosspayClientTest(
} }
context("실패 응답") { context("실패 응답") {
fun runTest(httpStatus: HttpStatus, expectedError: PaymentErrorCode) { fun runTest(httpStatus: HttpStatus) {
commonAction().andRespond { commonAction().andRespond {
withStatus(httpStatus) withStatus(httpStatus)
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
@ -75,7 +76,7 @@ class TosspayClientTest(
.createResponse(it) .createResponse(it)
} }
val exception = shouldThrow<PaymentException> { val exception = shouldThrow<ExternalPaymentException> {
client.confirm( client.confirm(
SampleTosspayConstant.PAYMENT_KEY, SampleTosspayConstant.PAYMENT_KEY,
SampleTosspayConstant.ORDER_ID, SampleTosspayConstant.ORDER_ID,
@ -83,15 +84,15 @@ class TosspayClientTest(
) )
} }
exception.errorCode shouldBe expectedError exception.errorCode shouldBe "ERROR_CODE"
} }
test("결제 서버에서 4XX 응답 시") { test("결제 서버에서 4XX 응답 시") {
runTest(HttpStatus.BAD_REQUEST, PaymentErrorCode.PAYMENT_CLIENT_ERROR) runTest(HttpStatus.BAD_REQUEST)
} }
test("결제 서버에서 5XX 응답 시") { test("결제 서버에서 5XX 응답 시") {
runTest(HttpStatus.INTERNAL_SERVER_ERROR, PaymentErrorCode.PAYMENT_PROVIDER_ERROR) runTest(HttpStatus.INTERNAL_SERVER_ERROR)
} }
} }
} }
@ -131,7 +132,7 @@ class TosspayClientTest(
} }
context("실패 응답") { context("실패 응답") {
fun runTest(httpStatus: HttpStatus, expectedError: PaymentErrorCode) { fun runTest(httpStatus: HttpStatus) {
commonAction().andRespond { commonAction().andRespond {
withStatus(httpStatus) withStatus(httpStatus)
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
@ -139,22 +140,22 @@ class TosspayClientTest(
.createResponse(it) .createResponse(it)
} }
val exception = shouldThrow<PaymentException> { val exception = shouldThrow<ExternalPaymentException> {
client.cancel( client.cancel(
SampleTosspayConstant.PAYMENT_KEY, SampleTosspayConstant.PAYMENT_KEY,
SampleTosspayConstant.AMOUNT, SampleTosspayConstant.AMOUNT,
SampleTosspayConstant.CANCEL_REASON SampleTosspayConstant.CANCEL_REASON
) )
} }
exception.errorCode shouldBe expectedError exception.errorCode shouldBe "ERROR_CODE"
} }
test("결제 서버에서 4XX 응답 시") { test("결제 서버에서 4XX 응답 시") {
runTest(HttpStatus.BAD_REQUEST, PaymentErrorCode.PAYMENT_CLIENT_ERROR) runTest(HttpStatus.BAD_REQUEST)
} }
test("결제 서버에서 5XX 응답 시") { test("결제 서버에서 5XX 응답 시") {
runTest(HttpStatus.INTERNAL_SERVER_ERROR, PaymentErrorCode.PAYMENT_PROVIDER_ERROR) runTest(HttpStatus.INTERNAL_SERVER_ERROR)
} }
} }
} }