[#41] 예약 스키마 재정의 #42

Merged
pricelees merged 41 commits from refactor/#41 into main 2025-09-09 00:43:39 +00:00
5 changed files with 62 additions and 49 deletions
Showing only changes of commit d62bd444f1 - Show all commits

View File

@ -15,7 +15,7 @@ import java.util.*
class PaymentConfig { class PaymentConfig {
@Bean @Bean
fun tossPaymentClientBuilder( fun tosspayClientBuilder(
paymentProperties: PaymentProperties, paymentProperties: PaymentProperties,
): RestClient.Builder { ): RestClient.Builder {
val settings: ClientHttpRequestFactorySettings = ClientHttpRequestFactorySettings.defaults().also { val settings: ClientHttpRequestFactorySettings = ClientHttpRequestFactorySettings.defaults().also {

View File

@ -1,22 +1,15 @@
package roomescape.payment.infrastructure.client.v2 package roomescape.payment.infrastructure.client
import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.annotation.JsonDeserialize import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import roomescape.payment.infrastructure.common.PaymentStatus import roomescape.payment.infrastructure.common.PaymentStatus
import roomescape.payment.infrastructure.persistence.v2.CanceledPaymentEntityV2 import roomescape.payment.infrastructure.persistence.CanceledPaymentEntity
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.OffsetDateTime import java.time.OffsetDateTime
data class PaymentCancelRequestV2( data class PaymentClientCancelResponse(
val paymentKey: String,
val amount: Int,
val cancelReason: String
)
data class PaymentCancelResponseV2(
val status: PaymentStatus, val status: PaymentStatus,
@JsonDeserialize(using = CancelDetailDeserializer::class) @JsonDeserialize(using = CancelDetailDeserializer::class)
val cancels: CancelDetail, val cancels: CancelDetail,
@ -36,7 +29,7 @@ fun CancelDetail.toEntity(
paymentId: Long, paymentId: Long,
canceledBy: Long, canceledBy: Long,
cancelRequestedAt: LocalDateTime cancelRequestedAt: LocalDateTime
) = CanceledPaymentEntityV2( ) = CanceledPaymentEntity(
id = id, id = id,
canceledAt = this.canceledAt, canceledAt = this.canceledAt,
requestedAt = cancelRequestedAt, requestedAt = cancelRequestedAt,
@ -49,7 +42,7 @@ fun CancelDetail.toEntity(
easypayDiscountAmount = this.easyPayDiscountAmount easypayDiscountAmount = this.easyPayDiscountAmount
) )
class CancelDetailDeserializer : JsonDeserializer<CancelDetail>() { class CancelDetailDeserializer : com.fasterxml.jackson.databind.JsonDeserializer<CancelDetail>() {
override fun deserialize( override fun deserialize(
p: JsonParser, p: JsonParser,
ctxt: DeserializationContext ctxt: DeserializationContext

View File

@ -1,4 +1,4 @@
package roomescape.payment.infrastructure.client.v2 package roomescape.payment.infrastructure.client
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.ObjectMapper
import io.github.oshai.kotlinlogging.KLogger import io.github.oshai.kotlinlogging.KLogger
@ -12,31 +12,40 @@ import org.springframework.web.client.ResponseErrorHandler
import org.springframework.web.client.RestClient import org.springframework.web.client.RestClient
import roomescape.payment.exception.PaymentErrorCode import roomescape.payment.exception.PaymentErrorCode
import roomescape.payment.exception.PaymentException import roomescape.payment.exception.PaymentException
import roomescape.payment.infrastructure.client.TossPaymentErrorResponse
import java.net.URI import java.net.URI
private val log: KLogger = KotlinLogging.logger {} private val log: KLogger = KotlinLogging.logger {}
@Component @Component
class TosspaymentClientV2( class TosspaymentClient(
objectMapper: ObjectMapper, objectMapper: ObjectMapper,
tossPaymentClientBuilder: RestClient.Builder tossPaymentClientBuilder: RestClient.Builder
) { ) {
private val confirmClient = ConfirmClient(objectMapper, tossPaymentClientBuilder.build()) private val confirmClient = ConfirmClient(objectMapper, tossPaymentClientBuilder.build())
private val cancelClient = CancelClient(objectMapper, tossPaymentClientBuilder.build()) private val cancelClient = CancelClient(objectMapper, tossPaymentClientBuilder.build())
fun confirm(request: PaymentConfirmRequest): PaymentConfirmResponse { fun confirm(
log.info { "[TossPaymentClientV2.confirm] 결제 승인 요청: request=$request" } paymentKey: String,
orderId: String,
amount: Int,
): PaymentClientConfirmResponse {
log.info { "[TossPaymentClient.confirm] 결제 승인 요청: paymentKey=$paymentKey, orderId=$orderId, amount=$amount" }
return confirmClient.request(request).also { return confirmClient.request(paymentKey, orderId, amount)
log.info { "[TossPaymentClientV2.confirm] 결제 승인 완료: response=$it" } .also {
} log.info { "[TossPaymentClient.confirm] 결제 승인 완료: response=$it" }
} }
fun cancel(request: PaymentCancelRequestV2): PaymentCancelResponseV2 { }
log.info { "[TossPaymentClient.cancel] 결제 취소 요청: request=$request" }
return cancelClient.request(request).also { fun cancel(
paymentKey: String,
amount: Int,
cancelReason: String
): PaymentClientCancelResponse {
log.info { "[TossPaymentClient.cancel] 결제 취소 요청: paymentKey=$paymentKey, amount=$amount, cancelReason=$cancelReason" }
return cancelClient.request(paymentKey, amount, cancelReason).also {
log.info { "[TossPaymentClient.cancel] 결제 취소 완료: response=$it" } log.info { "[TossPaymentClient.cancel] 결제 취소 완료: response=$it" }
} }
} }
@ -52,13 +61,20 @@ private class ConfirmClient(
private val errorHandler: TosspayErrorHandler = TosspayErrorHandler(objectMapper) private val errorHandler: TosspayErrorHandler = TosspayErrorHandler(objectMapper)
fun request(request: PaymentConfirmRequest): PaymentConfirmResponse = client.post() fun request(paymentKey: String, orderId: String, amount: Int): PaymentClientConfirmResponse = client.post()
.uri(CONFIRM_URI) .uri(CONFIRM_URI)
.contentType(MediaType.APPLICATION_JSON) .contentType(MediaType.APPLICATION_JSON)
.body(request) .body(
mapOf(
"paymentKey" to paymentKey,
"orderId" to orderId,
"amount" to amount
)
)
.retrieve() .retrieve()
.onStatus(errorHandler) .onStatus(errorHandler)
.body(PaymentConfirmResponse::class.java) ?: run { .body(PaymentClientConfirmResponse::class.java)
?: run {
log.error { "[TossPaymentConfirmClient.request] 응답 바디 변환 실패" } log.error { "[TossPaymentConfirmClient.request] 응답 바디 변환 실패" }
throw PaymentException(PaymentErrorCode.PAYMENT_UNEXPECTED_ERROR) throw PaymentException(PaymentErrorCode.PAYMENT_UNEXPECTED_ERROR)
} }
@ -74,17 +90,21 @@ private class CancelClient(
private val errorHandler: TosspayErrorHandler = TosspayErrorHandler(objectMapper) private val errorHandler: TosspayErrorHandler = TosspayErrorHandler(objectMapper)
fun request(request: PaymentCancelRequestV2): PaymentCancelResponseV2 = client.post() fun request(
.uri(CANCEL_URI, request.paymentKey) paymentKey: String,
amount: Int,
cancelReason: String
): PaymentClientCancelResponse = client.post()
.uri(CANCEL_URI, paymentKey)
.body( .body(
mapOf( mapOf(
"cancelReason" to request.cancelReason, "cancelReason" to cancelReason,
"cancelAmount" to request.amount, "cancelAmount" to amount,
) )
) )
.retrieve() .retrieve()
.onStatus(errorHandler) .onStatus(errorHandler)
.body(PaymentCancelResponseV2::class.java) .body(PaymentClientCancelResponse::class.java)
?: run { ?: run {
log.error { "[TossPaymentClient] 응답 바디 변환 실패" } log.error { "[TossPaymentClient] 응답 바디 변환 실패" }
throw PaymentException(PaymentErrorCode.PAYMENT_UNEXPECTED_ERROR) throw PaymentException(PaymentErrorCode.PAYMENT_UNEXPECTED_ERROR)

View File

@ -1,21 +1,15 @@
package roomescape.payment.infrastructure.client.v2 package roomescape.payment.infrastructure.client
import roomescape.payment.exception.PaymentErrorCode import roomescape.payment.exception.PaymentErrorCode
import roomescape.payment.exception.PaymentException import roomescape.payment.exception.PaymentException
import roomescape.payment.infrastructure.common.* import roomescape.payment.infrastructure.common.*
import roomescape.payment.infrastructure.persistence.v2.PaymentBankTransferDetailEntity import roomescape.payment.infrastructure.persistence.PaymentBankTransferDetailEntity
import roomescape.payment.infrastructure.persistence.v2.PaymentCardDetailEntity import roomescape.payment.infrastructure.persistence.PaymentCardDetailEntity
import roomescape.payment.infrastructure.persistence.v2.PaymentEasypayPrepaidDetailEntity import roomescape.payment.infrastructure.persistence.PaymentEasypayPrepaidDetailEntity
import roomescape.payment.infrastructure.persistence.v2.PaymentEntityV2 import roomescape.payment.infrastructure.persistence.PaymentEntity
import java.time.OffsetDateTime import java.time.OffsetDateTime
data class PaymentConfirmRequest( data class PaymentClientConfirmResponse(
val paymentKey: String,
val orderId: String,
val amount: Int,
)
data class PaymentConfirmResponse(
val paymentKey: String, val paymentKey: String,
val status: PaymentStatus, val status: PaymentStatus,
val totalAmount: Int, val totalAmount: Int,
@ -29,12 +23,12 @@ data class PaymentConfirmResponse(
val approvedAt: OffsetDateTime, val approvedAt: OffsetDateTime,
) )
fun PaymentConfirmResponse.toEntity( fun PaymentClientConfirmResponse.toEntity(
id: Long, id: Long,
reservationId: Long, reservationId: Long,
orderId: String, orderId: String,
paymentType: PaymentType paymentType: PaymentType
) = PaymentEntityV2( ) = PaymentEntity(
id = id, id = id,
reservationId = reservationId, reservationId = reservationId,
paymentKey = this.paymentKey, paymentKey = this.paymentKey,
@ -58,7 +52,7 @@ data class CardDetail(
val installmentPlanMonths: Int val installmentPlanMonths: Int
) )
fun PaymentConfirmResponse.toCardDetailEntity(id: Long, paymentId: Long): PaymentCardDetailEntity { fun PaymentClientConfirmResponse.toCardDetailEntity(id: Long, paymentId: Long): PaymentCardDetailEntity {
val cardDetail = this.card ?: throw PaymentException(PaymentErrorCode.PAYMENT_UNEXPECTED_ERROR) val cardDetail = this.card ?: throw PaymentException(PaymentErrorCode.PAYMENT_UNEXPECTED_ERROR)
return PaymentCardDetailEntity( return PaymentCardDetailEntity(
@ -85,7 +79,7 @@ data class EasyPayDetail(
val discountAmount: Int, val discountAmount: Int,
) )
fun PaymentConfirmResponse.toEasypayPrepaidDetailEntity( fun PaymentClientConfirmResponse.toEasypayPrepaidDetailEntity(
id: Long, id: Long,
paymentId: Long paymentId: Long
): PaymentEasypayPrepaidDetailEntity { ): PaymentEasypayPrepaidDetailEntity {
@ -107,7 +101,7 @@ data class TransferDetail(
val settlementStatus: String, val settlementStatus: String,
) )
fun PaymentConfirmResponse.toTransferDetailEntity( fun PaymentClientConfirmResponse.toTransferDetailEntity(
id: Long, id: Long,
paymentId: Long paymentId: Long
): PaymentBankTransferDetailEntity { ): PaymentBankTransferDetailEntity {

View File

@ -0,0 +1,6 @@
package roomescape.payment.infrastructure.client
data class TossPaymentErrorResponse(
val code: String,
val message: String
)