generated from pricelees/issue-pr-template
114 lines
4.4 KiB
Kotlin
114 lines
4.4 KiB
Kotlin
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.HttpStatus
|
|
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.common.exception.ErrorType
|
|
import roomescape.common.exception.RoomescapeException
|
|
import roomescape.payment.web.PaymentApprove
|
|
import roomescape.payment.web.PaymentCancel
|
|
import java.io.IOException
|
|
import java.util.Map
|
|
|
|
@Component
|
|
class TossPaymentClient(
|
|
private val log: KLogger = KotlinLogging.logger {},
|
|
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 confirmPayment(paymentRequest: PaymentApprove.Request): PaymentApprove.Response {
|
|
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) }
|
|
)
|
|
.body(PaymentApprove.Response::class.java)
|
|
?: throw RoomescapeException(ErrorType.PAYMENT_SERVER_ERROR, HttpStatus.INTERNAL_SERVER_ERROR)
|
|
}
|
|
|
|
fun cancelPayment(cancelRequest: PaymentCancel.Request): PaymentCancel.Response {
|
|
logPaymentCancelInfo(cancelRequest)
|
|
val param = Map.of<String, String>("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) }
|
|
)
|
|
.body(PaymentCancel.Response::class.java)
|
|
?: throw RoomescapeException(ErrorType.PAYMENT_SERVER_ERROR, HttpStatus.INTERNAL_SERVER_ERROR)
|
|
}
|
|
|
|
private fun logPaymentInfo(paymentRequest: PaymentApprove.Request) {
|
|
log.info {
|
|
"결제 승인 요청: paymentKey=${paymentRequest.paymentKey}, orderId=${paymentRequest.orderId}, " +
|
|
"amount=${paymentRequest.amount}, paymentType=${paymentRequest.paymentType}"
|
|
}
|
|
}
|
|
|
|
private fun logPaymentCancelInfo(cancelRequest: PaymentCancel.Request) {
|
|
log.info {
|
|
"결제 취소 요청: paymentKey=${cancelRequest.paymentKey}, amount=${cancelRequest.amount}, " +
|
|
"cancelReason=${cancelRequest.cancelReason}"
|
|
}
|
|
}
|
|
|
|
@Throws(IOException::class)
|
|
private fun handlePaymentError(
|
|
res: ClientHttpResponse
|
|
): Nothing {
|
|
val statusCode = res.statusCode
|
|
val errorType = getErrorTypeByStatusCode(statusCode)
|
|
val errorResponse = getErrorResponse(res)
|
|
|
|
throw RoomescapeException(
|
|
errorType,
|
|
"[ErrorCode = ${errorResponse.code}, ErrorMessage = ${errorResponse.message}]",
|
|
statusCode
|
|
)
|
|
}
|
|
|
|
@Throws(IOException::class)
|
|
private fun getErrorResponse(
|
|
res: ClientHttpResponse
|
|
): TossPaymentErrorResponse {
|
|
val body = res.body
|
|
val errorResponse = objectMapper.readValue(body, TossPaymentErrorResponse::class.java)
|
|
body.close()
|
|
return errorResponse
|
|
}
|
|
|
|
private fun getErrorTypeByStatusCode(
|
|
statusCode: HttpStatusCode
|
|
): ErrorType {
|
|
if (statusCode.is4xxClientError) {
|
|
return ErrorType.PAYMENT_ERROR
|
|
}
|
|
return ErrorType.PAYMENT_SERVER_ERROR
|
|
}
|
|
}
|