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

Merged
pricelees merged 45 commits from refactor/#56 into main 2025-10-09 09:33:29 +00:00
27 changed files with 387 additions and 344 deletions
Showing only changes of commit 1902fc6f7c - Show all commits

View File

@ -1,15 +1,19 @@
package com.sangdol.roomescape.payment.business
import com.sangdol.common.persistence.TransactionExecutionUtil
import com.sangdol.roomescape.payment.business.domain.PaymentClientError
import com.sangdol.roomescape.payment.business.domain.UserFacingPaymentErrorCode
import com.sangdol.roomescape.payment.dto.PaymentCancelRequest
import com.sangdol.roomescape.payment.exception.ExternalPaymentException
import com.sangdol.roomescape.payment.exception.PaymentErrorCode
import com.sangdol.roomescape.payment.exception.PaymentException
import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientCancelResponse
import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientConfirmResponse
import com.sangdol.roomescape.payment.dto.PaymentGatewayCancelResponse
import com.sangdol.roomescape.payment.dto.PaymentConfirmRequest
import com.sangdol.roomescape.payment.dto.PaymentCreateResponse
import com.sangdol.roomescape.payment.dto.PaymentGatewayResponse
import com.sangdol.roomescape.payment.dto.PaymentResponse
import com.sangdol.roomescape.payment.infrastructure.client.TosspayClient
import com.sangdol.roomescape.payment.infrastructure.persistence.*
import com.sangdol.roomescape.payment.web.*
import com.sangdol.roomescape.payment.mapper.toResponse
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
import org.springframework.stereotype.Service
@ -26,7 +30,7 @@ class PaymentService(
private val paymentWriter: PaymentWriter,
private val transactionExecutionUtil: TransactionExecutionUtil,
) {
fun requestConfirm(request: PaymentConfirmRequest): PaymentClientConfirmResponse {
fun requestConfirm(request: PaymentConfirmRequest): PaymentGatewayResponse {
try {
return paymentClient.confirm(request.paymentKey, request.orderId, request.amount)
} catch (e: ExternalPaymentException) {
@ -36,7 +40,7 @@ class PaymentService(
PaymentErrorCode.PAYMENT_PROVIDER_ERROR
}
val message = if (PaymentClientError.contains(e.errorCode)) {
val message = if (UserFacingPaymentErrorCode.contains(e.errorCode)) {
"${errorCode.message}(${e.message})"
} else {
errorCode.message
@ -48,13 +52,13 @@ class PaymentService(
fun savePayment(
reservationId: Long,
paymentConfirmResponse: PaymentClientConfirmResponse
paymentGatewayResponse: PaymentGatewayResponse
): PaymentCreateResponse {
val payment: PaymentEntity = paymentWriter.createPayment(
reservationId = reservationId,
paymentClientConfirmResponse = paymentConfirmResponse
paymentGatewayResponse = paymentGatewayResponse
)
val detail: PaymentDetailEntity = paymentWriter.createDetail(paymentConfirmResponse, payment.id)
val detail: PaymentDetailEntity = paymentWriter.createDetail(paymentGatewayResponse, payment.id)
return PaymentCreateResponse(paymentId = payment.id, detailId = detail.id)
}
@ -62,7 +66,7 @@ class PaymentService(
fun cancel(userId: Long, request: PaymentCancelRequest) {
val payment: PaymentEntity = findByReservationIdOrThrow(request.reservationId)
val clientCancelResponse: PaymentClientCancelResponse = paymentClient.cancel(
val clientCancelResponse: PaymentGatewayCancelResponse = paymentClient.cancel(
paymentKey = payment.paymentKey,
amount = payment.totalAmount,
cancelReason = request.cancelReason
@ -81,16 +85,16 @@ class PaymentService(
}
@Transactional(readOnly = true)
fun findDetailByReservationId(reservationId: Long): PaymentWithDetailResponse? {
fun findDetailByReservationId(reservationId: Long): PaymentResponse? {
log.info { "[findDetailByReservationId] 예약 결제 정보 조회 시작: reservationId=$reservationId" }
val payment: PaymentEntity? = findByReservationIdOrNull(reservationId)
val paymentDetail: PaymentDetailEntity? = payment?.let { findDetailByPaymentIdOrNull(it.id) }
val cancelDetail: CanceledPaymentEntity? = payment?.let { findCancelByPaymentIdOrNull(it.id) }
return payment?.toDetailResponse(
detail = paymentDetail?.toPaymentDetailResponse(),
cancel = cancelDetail?.toCancelDetailResponse()
return payment?.toResponse(
detail = paymentDetail?.toResponse(),
cancel = cancelDetail?.toResponse()
)
}

View File

@ -3,8 +3,13 @@ package com.sangdol.roomescape.payment.business
import com.sangdol.common.persistence.IDGenerator
import com.sangdol.roomescape.payment.exception.PaymentErrorCode
import com.sangdol.roomescape.payment.exception.PaymentException
import com.sangdol.roomescape.payment.infrastructure.client.*
import com.sangdol.roomescape.payment.infrastructure.common.PaymentMethod
import com.sangdol.roomescape.payment.business.domain.PaymentMethod
import com.sangdol.roomescape.payment.dto.PaymentGatewayCancelResponse
import com.sangdol.roomescape.payment.dto.PaymentGatewayResponse
import com.sangdol.roomescape.payment.mapper.toCardDetailEntity
import com.sangdol.roomescape.payment.mapper.toEasypayPrepaidDetailEntity
import com.sangdol.roomescape.payment.mapper.toEntity
import com.sangdol.roomescape.payment.mapper.toTransferDetailEntity
import com.sangdol.roomescape.payment.infrastructure.persistence.*
import io.github.oshai.kotlinlogging.KLogger
import io.github.oshai.kotlinlogging.KotlinLogging
@ -23,31 +28,31 @@ class PaymentWriter(
fun createPayment(
reservationId: Long,
paymentClientConfirmResponse: PaymentClientConfirmResponse
paymentGatewayResponse: PaymentGatewayResponse
): PaymentEntity {
log.info { "[PaymentWriterV2.createPayment] 결제 승인 및 결제 정보 저장 시작: reservationId=${reservationId}, paymentKey=${paymentClientConfirmResponse.paymentKey}" }
log.info { "[PaymentWriterV2.createPayment] 결제 승인 및 결제 정보 저장 시작: reservationId=${reservationId}, paymentKey=${paymentGatewayResponse.paymentKey}" }
return paymentClientConfirmResponse.toEntity(id = idGenerator.create(), reservationId = reservationId).also {
return paymentGatewayResponse.toEntity(id = idGenerator.create(), reservationId = reservationId).also {
paymentRepository.save(it)
log.info { "[PaymentWriterV2.createPayment] 결제 승인 및 결제 정보 저장 완료: reservationId=${reservationId}, payment.id=${it.id}" }
}
}
fun createDetail(
paymentResponse: PaymentClientConfirmResponse,
paymentGatewayResponse: PaymentGatewayResponse,
paymentId: Long,
): PaymentDetailEntity {
val method: PaymentMethod = paymentResponse.method
val method: PaymentMethod = paymentGatewayResponse.method
val id = idGenerator.create()
if (method == PaymentMethod.TRANSFER) {
return paymentDetailRepository.save(paymentResponse.toTransferDetailEntity(id, paymentId))
return paymentDetailRepository.save(paymentGatewayResponse.toTransferDetailEntity(id, paymentId))
}
if (method == PaymentMethod.EASY_PAY && paymentResponse.card == null) {
return paymentDetailRepository.save(paymentResponse.toEasypayPrepaidDetailEntity(id, paymentId))
if (method == PaymentMethod.EASY_PAY && paymentGatewayResponse.card == null) {
return paymentDetailRepository.save(paymentGatewayResponse.toEasypayPrepaidDetailEntity(id, paymentId))
}
if (paymentResponse.card != null) {
return paymentDetailRepository.save(paymentResponse.toCardDetailEntity(id, paymentId))
if (paymentGatewayResponse.card != null) {
return paymentDetailRepository.save(paymentGatewayResponse.toCardDetailEntity(id, paymentId))
}
throw PaymentException(PaymentErrorCode.NOT_SUPPORTED_PAYMENT_TYPE)
}
@ -56,7 +61,7 @@ class PaymentWriter(
userId: Long,
payment: PaymentEntity,
requestedAt: Instant,
cancelResponse: PaymentClientCancelResponse
cancelResponse: PaymentGatewayCancelResponse
): CanceledPaymentEntity {
log.debug { "[PaymentWriterV2.cancelPayment] 결제 취소 정보 저장 시작: payment.id=${payment.id}" }

View File

@ -1,4 +1,4 @@
package com.sangdol.roomescape.payment.infrastructure.common
package com.sangdol.roomescape.payment.business.domain
import com.fasterxml.jackson.annotation.JsonCreator
import com.sangdol.roomescape.payment.exception.PaymentErrorCode

View File

@ -1,6 +1,6 @@
package com.sangdol.roomescape.payment.business.domain
enum class PaymentClientError {
enum class UserFacingPaymentErrorCode {
ALREADY_PROCESSED_PAYMENT,
EXCEED_MAX_CARD_INSTALLMENT_PLAN,
NOT_ALLOWED_POINT_USE,

View File

@ -4,9 +4,9 @@ import com.sangdol.common.types.web.CommonApiResponse
import com.sangdol.roomescape.auth.web.support.User
import com.sangdol.roomescape.auth.web.support.UserOnly
import com.sangdol.roomescape.common.types.CurrentUserContext
import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientConfirmResponse
import com.sangdol.roomescape.payment.web.PaymentCancelRequest
import com.sangdol.roomescape.payment.web.PaymentConfirmRequest
import com.sangdol.roomescape.payment.dto.PaymentGatewayResponse
import com.sangdol.roomescape.payment.dto.PaymentCancelRequest
import com.sangdol.roomescape.payment.dto.PaymentConfirmRequest
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
@ -21,7 +21,7 @@ interface PaymentAPI {
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
fun confirmPayment(
@Valid @RequestBody request: PaymentConfirmRequest
): ResponseEntity<CommonApiResponse<PaymentClientConfirmResponse>>
): ResponseEntity<CommonApiResponse<PaymentGatewayResponse>>
@Operation(summary = "결제 취소")
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))

View File

@ -0,0 +1,59 @@
package com.sangdol.roomescape.payment.dto
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.sangdol.roomescape.payment.business.domain.*
import com.sangdol.roomescape.payment.infrastructure.client.CancelDetailDeserializer
import java.time.OffsetDateTime
data class PaymentGatewayResponse(
val paymentKey: String,
val orderId: String,
val type: PaymentType,
val status: PaymentStatus,
val totalAmount: Int,
val vat: Int,
val suppliedAmount: Int,
val method: PaymentMethod,
val card: CardDetailResponse?,
val easyPay: EasyPayDetailResponse?,
val transfer: TransferDetailResponse?,
val requestedAt: OffsetDateTime,
val approvedAt: OffsetDateTime,
)
data class PaymentGatewayCancelResponse(
val status: PaymentStatus,
@JsonDeserialize(using = CancelDetailDeserializer::class)
val cancels: CancelDetail,
)
data class CardDetailResponse(
val issuerCode: CardIssuerCode,
val number: String,
val amount: Int,
val cardType: CardType,
val ownerType: CardOwnerType,
val isInterestFree: Boolean,
val approveNo: String,
val installmentPlanMonths: Int
)
data class EasyPayDetailResponse(
val provider: EasyPayCompanyCode,
val amount: Int,
val discountAmount: Int,
)
data class TransferDetailResponse(
val bankCode: BankCode,
val settlementStatus: String,
)
data class CancelDetail(
val cancelAmount: Int,
val cardDiscountAmount: Int,
val transferDiscountAmount: Int,
val easyPayDiscountAmount: Int,
val canceledAt: OffsetDateTime,
val cancelReason: String
)

View File

@ -0,0 +1,49 @@
package com.sangdol.roomescape.payment.dto
import com.sangdol.roomescape.payment.business.domain.PaymentStatus
import java.time.Instant
data class PaymentResponse(
val orderId: String,
val totalAmount: Int,
val method: String,
val status: PaymentStatus,
val requestedAt: Instant,
val approvedAt: Instant,
val detail: PaymentDetailResponse?,
val cancel: PaymentCancelDetailResponse?,
)
sealed class PaymentDetailResponse {
data class CardDetailResponse(
val type: String = "CARD",
val issuerCode: String,
val cardType: String,
val ownerType: String,
val cardNumber: String,
val amount: Int,
val approvalNumber: String,
val installmentPlanMonths: Int,
val easypayProviderName: String?,
val easypayDiscountAmount: Int?,
) : PaymentDetailResponse()
data class BankTransferDetailResponse(
val type: String = "BANK_TRANSFER",
val bankName: String,
) : PaymentDetailResponse()
data class EasyPayPrepaidDetailResponse(
val type: String = "EASYPAY_PREPAID",
val providerName: String,
val amount: Int,
val discountAmount: Int,
) : PaymentDetailResponse()
}
data class PaymentCancelDetailResponse(
val cancellationRequestedAt: Instant,
val cancellationApprovedAt: Instant?,
val cancelReason: String,
val canceledBy: Long,
)

View File

@ -0,0 +1,20 @@
package com.sangdol.roomescape.payment.dto
import java.time.Instant
data class PaymentConfirmRequest(
val paymentKey: String,
val orderId: String,
val amount: Int,
)
data class PaymentCreateResponse(
val paymentId: Long,
val detailId: Long
)
data class PaymentCancelRequest(
val reservationId: Long,
val cancelReason: String,
val requestedAt: Instant = Instant.now()
)

View File

@ -1,67 +0,0 @@
package com.sangdol.roomescape.payment.infrastructure.client
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
import com.sangdol.roomescape.payment.infrastructure.common.PaymentStatus
import com.sangdol.roomescape.payment.infrastructure.persistence.CanceledPaymentEntity
import java.time.Instant
import java.time.OffsetDateTime
data class PaymentClientCancelResponse(
val status: PaymentStatus,
@JsonDeserialize(using = CancelDetailDeserializer::class)
val cancels: CancelDetail,
)
data class CancelDetail(
val cancelAmount: Int,
val cardDiscountAmount: Int,
val transferDiscountAmount: Int,
val easyPayDiscountAmount: Int,
val canceledAt: OffsetDateTime,
val cancelReason: String
)
fun CancelDetail.toEntity(
id: Long,
paymentId: Long,
canceledBy: Long,
cancelRequestedAt: Instant
) = CanceledPaymentEntity(
id = id,
canceledAt = this.canceledAt.toInstant(),
requestedAt = cancelRequestedAt,
paymentId = paymentId,
canceledBy = canceledBy,
cancelReason = this.cancelReason,
cancelAmount = this.cancelAmount,
cardDiscountAmount = this.cardDiscountAmount,
transferDiscountAmount = this.transferDiscountAmount,
easypayDiscountAmount = this.easyPayDiscountAmount
)
class CancelDetailDeserializer : com.fasterxml.jackson.databind.JsonDeserializer<CancelDetail>() {
override fun deserialize(
p: JsonParser,
ctxt: DeserializationContext
): CancelDetail? {
val node: JsonNode = p.codec.readTree(p) ?: return null
val targetNode = when {
node.isArray && !node.isEmpty -> node[0]
node.isObject -> node
else -> return null
}
return CancelDetail(
cancelAmount = targetNode.get("cancelAmount").asInt(),
cardDiscountAmount = targetNode.get("cardDiscountAmount").asInt(),
transferDiscountAmount = targetNode.get("transferDiscountAmount").asInt(),
easyPayDiscountAmount = targetNode.get("easyPayDiscountAmount").asInt(),
canceledAt = OffsetDateTime.parse(targetNode.get("canceledAt").asText()),
cancelReason = targetNode.get("cancelReason").asText()
)
}
}

View File

@ -1,6 +1,8 @@
package com.sangdol.roomescape.payment.infrastructure.client
import com.fasterxml.jackson.databind.ObjectMapper
import com.sangdol.roomescape.payment.dto.PaymentGatewayCancelResponse
import com.sangdol.roomescape.payment.dto.PaymentGatewayResponse
import com.sangdol.roomescape.payment.exception.ExternalPaymentException
import com.sangdol.roomescape.payment.exception.PaymentErrorCode
import com.sangdol.roomescape.payment.exception.PaymentException
@ -29,7 +31,7 @@ class TosspayClient(
paymentKey: String,
orderId: String,
amount: Int,
): PaymentClientConfirmResponse {
): PaymentGatewayResponse {
val startTime = System.currentTimeMillis()
log.info { "[TosspayClient.confirm] 결제 승인 요청: paymentKey=$paymentKey, orderId=$orderId, amount=$amount" }
@ -43,7 +45,7 @@ class TosspayClient(
paymentKey: String,
amount: Int,
cancelReason: String
): PaymentClientCancelResponse {
): PaymentGatewayCancelResponse {
val startTime = System.currentTimeMillis()
log.info { "[TosspayClient.cancel] 결제 취소 요청: paymentKey=$paymentKey, amount=$amount, cancelReason=$cancelReason" }
@ -63,7 +65,7 @@ private class ConfirmClient(
private val errorHandler: TosspayErrorHandler = TosspayErrorHandler(objectMapper)
fun request(paymentKey: String, orderId: String, amount: Int): PaymentClientConfirmResponse {
fun request(paymentKey: String, orderId: String, amount: Int): PaymentGatewayResponse {
val response = client.post()
.uri(CONFIRM_URI)
.contentType(MediaType.APPLICATION_JSON)
@ -84,7 +86,7 @@ private class ConfirmClient(
log.debug { "[TosspayClient.confirm] 응답 수신: json = $response" }
return objectMapper.readValue(response, PaymentClientConfirmResponse::class.java)
return objectMapper.readValue(response, PaymentGatewayResponse::class.java)
}
}
@ -102,7 +104,7 @@ private class CancelClient(
paymentKey: String,
amount: Int,
cancelReason: String
): PaymentClientCancelResponse {
): PaymentGatewayCancelResponse {
val response = client.post()
.uri(CANCEL_URI, paymentKey)
.body(
@ -120,7 +122,7 @@ private class CancelClient(
}
log.debug { "[TosspayClient.cancel] 응답 수신: json = $response" }
return objectMapper.readValue(response, PaymentClientCancelResponse::class.java)
return objectMapper.readValue(response, PaymentGatewayCancelResponse::class.java)
}
}

View File

@ -0,0 +1,32 @@
package com.sangdol.roomescape.payment.infrastructure.client
import com.fasterxml.jackson.core.JsonParser
import com.fasterxml.jackson.databind.DeserializationContext
import com.fasterxml.jackson.databind.JsonDeserializer
import com.fasterxml.jackson.databind.JsonNode
import com.sangdol.roomescape.payment.dto.CancelDetail
import java.time.OffsetDateTime
class CancelDetailDeserializer : JsonDeserializer<CancelDetail>() {
override fun deserialize(
p: JsonParser,
ctxt: DeserializationContext
): CancelDetail? {
val node: JsonNode = p.codec.readTree(p) ?: return null
val targetNode = when {
node.isArray && !node.isEmpty -> node[0]
node.isObject -> node
else -> return null
}
return CancelDetail(
cancelAmount = targetNode.get("cancelAmount").asInt(),
cardDiscountAmount = targetNode.get("cardDiscountAmount").asInt(),
transferDiscountAmount = targetNode.get("transferDiscountAmount").asInt(),
easyPayDiscountAmount = targetNode.get("easyPayDiscountAmount").asInt(),
canceledAt = OffsetDateTime.parse(targetNode.get("canceledAt").asText()),
cancelReason = targetNode.get("cancelReason").asText()
)
}
}

View File

@ -1,7 +1,11 @@
package com.sangdol.roomescape.payment.infrastructure.persistence
import com.sangdol.common.persistence.PersistableBaseEntity
import com.sangdol.roomescape.payment.infrastructure.common.*
import com.sangdol.roomescape.payment.business.domain.BankCode
import com.sangdol.roomescape.payment.business.domain.CardIssuerCode
import com.sangdol.roomescape.payment.business.domain.CardOwnerType
import com.sangdol.roomescape.payment.business.domain.CardType
import com.sangdol.roomescape.payment.business.domain.EasyPayCompanyCode
import jakarta.persistence.*
@Entity

View File

@ -1,9 +1,9 @@
package com.sangdol.roomescape.payment.infrastructure.persistence
import com.sangdol.common.persistence.PersistableBaseEntity
import com.sangdol.roomescape.payment.infrastructure.common.PaymentMethod
import com.sangdol.roomescape.payment.infrastructure.common.PaymentStatus
import com.sangdol.roomescape.payment.infrastructure.common.PaymentType
import com.sangdol.roomescape.payment.business.domain.PaymentMethod
import com.sangdol.roomescape.payment.business.domain.PaymentStatus
import com.sangdol.roomescape.payment.business.domain.PaymentType
import jakarta.persistence.Entity
import jakarta.persistence.EnumType
import jakarta.persistence.Enumerated

View File

@ -1,31 +1,13 @@
package com.sangdol.roomescape.payment.infrastructure.client
package com.sangdol.roomescape.payment.mapper
import com.sangdol.roomescape.payment.dto.CancelDetail
import com.sangdol.roomescape.payment.dto.PaymentGatewayResponse
import com.sangdol.roomescape.payment.exception.PaymentErrorCode
import com.sangdol.roomescape.payment.exception.PaymentException
import com.sangdol.roomescape.payment.infrastructure.common.*
import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentBankTransferDetailEntity
import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentCardDetailEntity
import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentEasypayPrepaidDetailEntity
import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentEntity
import java.time.OffsetDateTime
import com.sangdol.roomescape.payment.infrastructure.persistence.*
import java.time.Instant
data class PaymentClientConfirmResponse(
val paymentKey: String,
val orderId: String,
val type: PaymentType,
val status: PaymentStatus,
val totalAmount: Int,
val vat: Int,
val suppliedAmount: Int,
val method: PaymentMethod,
val card: CardDetail?,
val easyPay: EasyPayDetail?,
val transfer: TransferDetail?,
val requestedAt: OffsetDateTime,
val approvedAt: OffsetDateTime,
)
fun PaymentClientConfirmResponse.toEntity(
fun PaymentGatewayResponse.toEntity(
id: Long,
reservationId: Long,
) = PaymentEntity(
@ -41,18 +23,7 @@ fun PaymentClientConfirmResponse.toEntity(
status = this.status,
)
data class CardDetail(
val issuerCode: CardIssuerCode,
val number: String,
val amount: Int,
val cardType: CardType,
val ownerType: CardOwnerType,
val isInterestFree: Boolean,
val approveNo: String,
val installmentPlanMonths: Int
)
fun PaymentClientConfirmResponse.toCardDetailEntity(id: Long, paymentId: Long): PaymentCardDetailEntity {
fun PaymentGatewayResponse.toCardDetailEntity(id: Long, paymentId: Long): PaymentCardDetailEntity {
val cardDetail = this.card ?: throw PaymentException(PaymentErrorCode.PAYMENT_UNEXPECTED_ERROR)
return PaymentCardDetailEntity(
@ -73,13 +44,7 @@ fun PaymentClientConfirmResponse.toCardDetailEntity(id: Long, paymentId: Long):
)
}
data class EasyPayDetail(
val provider: EasyPayCompanyCode,
val amount: Int,
val discountAmount: Int,
)
fun PaymentClientConfirmResponse.toEasypayPrepaidDetailEntity(
fun PaymentGatewayResponse.toEasypayPrepaidDetailEntity(
id: Long,
paymentId: Long
): PaymentEasypayPrepaidDetailEntity {
@ -96,12 +61,7 @@ fun PaymentClientConfirmResponse.toEasypayPrepaidDetailEntity(
)
}
data class TransferDetail(
val bankCode: BankCode,
val settlementStatus: String,
)
fun PaymentClientConfirmResponse.toTransferDetailEntity(
fun PaymentGatewayResponse.toTransferDetailEntity(
id: Long,
paymentId: Long
): PaymentBankTransferDetailEntity {
@ -116,3 +76,21 @@ fun PaymentClientConfirmResponse.toTransferDetailEntity(
settlementStatus = transferDetail.settlementStatus
)
}
fun CancelDetail.toEntity(
id: Long,
paymentId: Long,
canceledBy: Long,
cancelRequestedAt: Instant
) = CanceledPaymentEntity(
id = id,
canceledAt = this.canceledAt.toInstant(),
requestedAt = cancelRequestedAt,
paymentId = paymentId,
canceledBy = canceledBy,
cancelReason = this.cancelReason,
cancelAmount = this.cancelAmount,
cardDiscountAmount = this.cardDiscountAmount,
transferDiscountAmount = this.transferDiscountAmount,
easypayDiscountAmount = this.easyPayDiscountAmount
)

View File

@ -0,0 +1,70 @@
package com.sangdol.roomescape.payment.mapper
import com.sangdol.roomescape.payment.dto.PaymentCancelDetailResponse
import com.sangdol.roomescape.payment.dto.PaymentDetailResponse
import com.sangdol.roomescape.payment.dto.PaymentResponse
import com.sangdol.roomescape.payment.exception.PaymentErrorCode
import com.sangdol.roomescape.payment.exception.PaymentException
import com.sangdol.roomescape.payment.infrastructure.persistence.*
fun PaymentEntity.toResponse(
detail: PaymentDetailResponse?,
cancel: PaymentCancelDetailResponse?
): PaymentResponse {
return PaymentResponse(
orderId = this.orderId,
totalAmount = this.totalAmount,
method = this.method.koreanName,
status = this.status,
requestedAt = this.requestedAt,
approvedAt = this.approvedAt,
detail = detail,
cancel = cancel
)
}
fun PaymentDetailEntity.toResponse(): PaymentDetailResponse {
return when (this) {
is PaymentCardDetailEntity -> this.toResponse()
is PaymentBankTransferDetailEntity -> this.toResponse()
is PaymentEasypayPrepaidDetailEntity -> this.toResponse()
else -> throw PaymentException(PaymentErrorCode.NOT_SUPPORTED_PAYMENT_TYPE)
}
}
fun PaymentCardDetailEntity.toResponse(): PaymentDetailResponse.CardDetailResponse {
return PaymentDetailResponse.CardDetailResponse(
issuerCode = this.issuerCode.koreanName,
cardType = this.cardType.koreanName,
ownerType = this.ownerType.koreanName,
cardNumber = this.cardNumber,
amount = this.amount,
approvalNumber = this.approvalNumber,
installmentPlanMonths = this.installmentPlanMonths,
easypayProviderName = this.easypayProviderCode?.koreanName,
easypayDiscountAmount = this.easypayDiscountAmount
)
}
fun PaymentBankTransferDetailEntity.toResponse(): PaymentDetailResponse.BankTransferDetailResponse {
return PaymentDetailResponse.BankTransferDetailResponse(
bankName = this.bankCode.koreanName
)
}
fun PaymentEasypayPrepaidDetailEntity.toResponse(): PaymentDetailResponse.EasyPayPrepaidDetailResponse {
return PaymentDetailResponse.EasyPayPrepaidDetailResponse(
providerName = this.easypayProviderCode.koreanName,
amount = this.amount,
discountAmount = this.discountAmount
)
}
fun CanceledPaymentEntity.toResponse(): PaymentCancelDetailResponse {
return PaymentCancelDetailResponse(
cancellationRequestedAt = this.requestedAt,
cancellationApprovedAt = this.canceledAt,
cancelReason = this.cancelReason,
canceledBy = this.canceledBy
)
}

View File

@ -5,7 +5,9 @@ import com.sangdol.roomescape.auth.web.support.User
import com.sangdol.roomescape.common.types.CurrentUserContext
import com.sangdol.roomescape.payment.business.PaymentService
import com.sangdol.roomescape.payment.docs.PaymentAPI
import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientConfirmResponse
import com.sangdol.roomescape.payment.dto.PaymentCancelRequest
import com.sangdol.roomescape.payment.dto.PaymentConfirmRequest
import com.sangdol.roomescape.payment.dto.PaymentGatewayResponse
import jakarta.validation.Valid
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
@ -19,7 +21,7 @@ class PaymentController(
@PostMapping("/confirm")
override fun confirmPayment(
@Valid @RequestBody request: PaymentConfirmRequest
): ResponseEntity<CommonApiResponse<PaymentClientConfirmResponse>> {
): ResponseEntity<CommonApiResponse<PaymentGatewayResponse>> {
val response = paymentService.requestConfirm(request)
return ResponseEntity.ok(CommonApiResponse(response))

View File

@ -1,134 +0,0 @@
package com.sangdol.roomescape.payment.web
import com.sangdol.roomescape.payment.exception.PaymentErrorCode
import com.sangdol.roomescape.payment.exception.PaymentException
import com.sangdol.roomescape.payment.infrastructure.common.PaymentStatus
import com.sangdol.roomescape.payment.infrastructure.common.PaymentType
import com.sangdol.roomescape.payment.infrastructure.persistence.*
import com.sangdol.roomescape.payment.web.PaymentDetailResponse.*
import java.time.Instant
data class PaymentConfirmRequest(
val paymentKey: String,
val orderId: String,
val amount: Int,
)
data class PaymentCreateResponse(
val paymentId: Long,
val detailId: Long
)
data class PaymentCancelRequest(
val reservationId: Long,
val cancelReason: String,
val requestedAt: Instant = Instant.now()
)
data class PaymentWithDetailResponse(
val orderId: String,
val totalAmount: Int,
val method: String,
val status: PaymentStatus,
val requestedAt: Instant,
val approvedAt: Instant,
val detail: PaymentDetailResponse?,
val cancel: PaymentCancelDetailResponse?,
)
fun PaymentEntity.toDetailResponse(
detail: PaymentDetailResponse?,
cancel: PaymentCancelDetailResponse?
): PaymentWithDetailResponse {
return PaymentWithDetailResponse(
orderId = this.orderId,
totalAmount = this.totalAmount,
method = this.method.koreanName,
status = this.status,
requestedAt = this.requestedAt,
approvedAt = this.approvedAt,
detail = detail,
cancel = cancel
)
}
sealed class PaymentDetailResponse {
data class CardDetailResponse(
val type: String = "CARD",
val issuerCode: String,
val cardType: String,
val ownerType: String,
val cardNumber: String,
val amount: Int,
val approvalNumber: String,
val installmentPlanMonths: Int,
val easypayProviderName: String?,
val easypayDiscountAmount: Int?,
) : PaymentDetailResponse()
data class BankTransferDetailResponse(
val type: String = "BANK_TRANSFER",
val bankName: String,
) : PaymentDetailResponse()
data class EasyPayPrepaidDetailResponse(
val type: String = "EASYPAY_PREPAID",
val providerName: String,
val amount: Int,
val discountAmount: Int,
) : PaymentDetailResponse()
}
fun PaymentDetailEntity.toPaymentDetailResponse(): PaymentDetailResponse {
return when (this) {
is PaymentCardDetailEntity -> this.toCardDetailResponse()
is PaymentBankTransferDetailEntity -> this.toBankTransferDetailResponse()
is PaymentEasypayPrepaidDetailEntity -> this.toEasyPayPrepaidDetailResponse()
else -> throw PaymentException(PaymentErrorCode.NOT_SUPPORTED_PAYMENT_TYPE)
}
}
fun PaymentCardDetailEntity.toCardDetailResponse(): CardDetailResponse {
return CardDetailResponse(
issuerCode = this.issuerCode.koreanName,
cardType = this.cardType.koreanName,
ownerType = this.ownerType.koreanName,
cardNumber = this.cardNumber,
amount = this.amount,
approvalNumber = this.approvalNumber,
installmentPlanMonths = this.installmentPlanMonths,
easypayProviderName = this.easypayProviderCode?.koreanName,
easypayDiscountAmount = this.easypayDiscountAmount
)
}
fun PaymentBankTransferDetailEntity.toBankTransferDetailResponse(): BankTransferDetailResponse {
return BankTransferDetailResponse(
bankName = this.bankCode.koreanName
)
}
fun PaymentEasypayPrepaidDetailEntity.toEasyPayPrepaidDetailResponse(): EasyPayPrepaidDetailResponse {
return EasyPayPrepaidDetailResponse(
providerName = this.easypayProviderCode.koreanName,
amount = this.amount,
discountAmount = this.discountAmount
)
}
data class PaymentCancelDetailResponse(
val cancellationRequestedAt: Instant,
val cancellationApprovedAt: Instant?,
val cancelReason: String,
val canceledBy: Long,
)
fun CanceledPaymentEntity.toCancelDetailResponse(): PaymentCancelDetailResponse {
return PaymentCancelDetailResponse(
cancellationRequestedAt = this.requestedAt,
cancellationApprovedAt = this.canceledAt,
cancelReason = this.cancelReason,
canceledBy = this.canceledBy
)
}

View File

@ -3,7 +3,7 @@ package com.sangdol.roomescape.reservation.business
import com.sangdol.common.persistence.IDGenerator
import com.sangdol.roomescape.common.types.CurrentUserContext
import com.sangdol.roomescape.payment.business.PaymentService
import com.sangdol.roomescape.payment.web.PaymentWithDetailResponse
import com.sangdol.roomescape.payment.dto.PaymentResponse
import com.sangdol.roomescape.reservation.dto.PendingReservationCreateRequest
import com.sangdol.roomescape.reservation.dto.PendingReservationCreateResponse
import com.sangdol.roomescape.reservation.dto.ReservationCancelRequest
@ -132,7 +132,7 @@ class ReservationService(
val reservation: ReservationEntity = findOrThrow(id)
val user: UserContactResponse = userService.findContactById(reservation.userId)
val paymentDetail: PaymentWithDetailResponse? = paymentService.findDetailByReservationId(id)
val paymentDetail: PaymentResponse? = paymentService.findDetailByReservationId(id)
return reservation.toAdditionalResponse(
user = user,

View File

@ -1,6 +1,6 @@
package com.sangdol.roomescape.reservation.dto
import com.sangdol.roomescape.payment.web.PaymentWithDetailResponse
import com.sangdol.roomescape.payment.dto.PaymentResponse
import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationStatus
import com.sangdol.roomescape.user.dto.UserContactResponse
import java.time.Instant
@ -22,7 +22,7 @@ data class ReservationAdditionalResponse(
val reserver: ReserverInfo,
val user: UserContactResponse,
val applicationDateTime: Instant,
val payment: PaymentWithDetailResponse?,
val payment: PaymentResponse?,
)
data class ReserverInfo(

View File

@ -1,6 +1,6 @@
package com.sangdol.roomescape.reservation.mapper
import com.sangdol.roomescape.payment.web.PaymentWithDetailResponse
import com.sangdol.roomescape.payment.dto.PaymentResponse
import com.sangdol.roomescape.reservation.dto.PendingReservationCreateRequest
import com.sangdol.roomescape.reservation.dto.ReservationAdditionalResponse
import com.sangdol.roomescape.reservation.dto.ReservationOverviewResponse
@ -40,7 +40,7 @@ fun ReservationEntity.toOverviewResponse(
fun ReservationEntity.toAdditionalResponse(
user: UserContactResponse,
payment: PaymentWithDetailResponse?,
payment: PaymentResponse?,
): ReservationAdditionalResponse {
return ReservationAdditionalResponse(
id = this.id,

View File

@ -6,7 +6,14 @@ import com.sangdol.common.utils.KoreaDateTime
import com.sangdol.roomescape.admin.infrastructure.persistence.AdminEntity
import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel
import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType
import com.sangdol.roomescape.payment.infrastructure.common.*
import com.sangdol.roomescape.payment.business.domain.BankCode
import com.sangdol.roomescape.payment.business.domain.CardIssuerCode
import com.sangdol.roomescape.payment.business.domain.CardOwnerType
import com.sangdol.roomescape.payment.business.domain.CardType
import com.sangdol.roomescape.payment.business.domain.EasyPayCompanyCode
import com.sangdol.roomescape.payment.business.domain.PaymentMethod
import com.sangdol.roomescape.payment.business.domain.PaymentStatus
import com.sangdol.roomescape.payment.business.domain.PaymentType
import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationStatus
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus
import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity

View File

@ -11,7 +11,7 @@
//import com.sangdol.roomescape.payment.infrastructure.client.TransferDetail
//import com.sangdol.roomescape.payment.infrastructure.common.*
//import com.sangdol.roomescape.payment.infrastructure.persistence.*
//import com.sangdol.roomescape.payment.web.PaymentConfirmRequest
//import com.sangdol.roomescape.payment.dto.PaymentConfirmRequest
//import com.sangdol.roomescape.payment.web.PaymentCreateResponse
//import com.sangdol.roomescape.supports.*
//import io.kotest.matchers.shouldBe

View File

@ -1,8 +1,15 @@
package com.sangdol.roomescape.payment
import com.sangdol.roomescape.payment.business.domain.BankCode
import com.sangdol.roomescape.payment.business.domain.CardIssuerCode
import com.sangdol.roomescape.payment.business.domain.CardOwnerType
import com.sangdol.roomescape.payment.business.domain.CardType
import com.sangdol.roomescape.payment.business.domain.EasyPayCompanyCode
import com.sangdol.roomescape.payment.business.domain.PaymentMethod
import com.sangdol.roomescape.payment.business.domain.PaymentStatus
import com.sangdol.roomescape.payment.business.domain.PaymentType
import com.sangdol.roomescape.payment.exception.PaymentErrorCode
import com.sangdol.roomescape.payment.exception.PaymentException
import com.sangdol.roomescape.payment.infrastructure.common.*
import io.kotest.assertions.assertSoftly
import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe

View File

@ -2,12 +2,10 @@ package com.sangdol.roomescape.payment
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.PaymentException
import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientCancelResponse
import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientConfirmResponse
import com.sangdol.roomescape.payment.dto.PaymentGatewayCancelResponse
import com.sangdol.roomescape.payment.dto.PaymentGatewayResponse
import com.sangdol.roomescape.payment.infrastructure.client.TosspayClient
import com.sangdol.roomescape.payment.infrastructure.common.PaymentStatus
import com.sangdol.roomescape.payment.business.domain.PaymentStatus
import io.kotest.assertions.assertSoftly
import io.kotest.assertions.throwables.shouldThrow
import io.kotest.core.spec.style.FunSpec
@ -116,7 +114,7 @@ class TosspayClientTest(
.createResponse(it)
}
val cancelResponse: PaymentClientCancelResponse = client.cancel(
val cancelResponse: PaymentGatewayCancelResponse = client.cancel(
SampleTosspayConstant.PAYMENT_KEY,
SampleTosspayConstant.AMOUNT,
SampleTosspayConstant.CANCEL_REASON
@ -162,13 +160,13 @@ class TosspayClientTest(
}
fun runConfirmTest() {
val paymentResponse: PaymentClientConfirmResponse = client.confirm(
val paymentGatewayResponse: PaymentGatewayResponse = client.confirm(
SampleTosspayConstant.PAYMENT_KEY,
SampleTosspayConstant.ORDER_ID,
SampleTosspayConstant.AMOUNT
)
assertSoftly(paymentResponse) {
assertSoftly(paymentGatewayResponse) {
this.paymentKey shouldBe SampleTosspayConstant.PAYMENT_KEY
this.totalAmount shouldBe SampleTosspayConstant.AMOUNT
}

View File

@ -5,9 +5,9 @@ import com.sangdol.common.types.web.HttpStatus
import com.sangdol.common.utils.KoreaDate
import com.sangdol.common.utils.KoreaTime
import com.sangdol.roomescape.auth.exception.AuthErrorCode
import com.sangdol.roomescape.payment.infrastructure.common.BankCode
import com.sangdol.roomescape.payment.infrastructure.common.CardIssuerCode
import com.sangdol.roomescape.payment.infrastructure.common.EasyPayCompanyCode
import com.sangdol.roomescape.payment.business.domain.BankCode
import com.sangdol.roomescape.payment.business.domain.CardIssuerCode
import com.sangdol.roomescape.payment.business.domain.EasyPayCompanyCode
import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentDetailRepository
import com.sangdol.roomescape.reservation.exception.ReservationErrorCode
import com.sangdol.roomescape.reservation.infrastructure.persistence.CanceledReservationRepository

View File

@ -1,32 +1,27 @@
package com.sangdol.roomescape.supports
import com.sangdol.roomescape.payment.business.PaymentWriter
import com.sangdol.roomescape.payment.infrastructure.client.CardDetail
import com.sangdol.roomescape.payment.infrastructure.client.EasyPayDetail
import com.sangdol.roomescape.payment.infrastructure.client.TransferDetail
import com.sangdol.roomescape.payment.infrastructure.common.PaymentMethod
import com.sangdol.roomescape.payment.business.domain.PaymentMethod
import com.sangdol.roomescape.payment.dto.*
import com.sangdol.roomescape.payment.infrastructure.persistence.CanceledPaymentEntity
import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentEntity
import com.sangdol.roomescape.payment.infrastructure.persistence.PaymentRepository
import com.sangdol.roomescape.payment.web.PaymentConfirmRequest
import com.sangdol.roomescape.payment.web.PaymentWithDetailResponse
import com.sangdol.roomescape.payment.web.toDetailResponse
import com.sangdol.roomescape.payment.web.toPaymentDetailResponse
import com.sangdol.roomescape.payment.mapper.toResponse
import com.sangdol.roomescape.reservation.dto.PendingReservationCreateRequest
import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationEntity
import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationRepository
import com.sangdol.roomescape.reservation.infrastructure.persistence.ReservationStatus
import com.sangdol.roomescape.reservation.dto.PendingReservationCreateRequest
import com.sangdol.roomescape.reservation.mapper.toEntity
import com.sangdol.roomescape.schedule.dto.ScheduleCreateRequest
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleRepository
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus
import com.sangdol.roomescape.schedule.dto.ScheduleCreateRequest
import com.sangdol.roomescape.store.infrastructure.persistence.StoreEntity
import com.sangdol.roomescape.store.infrastructure.persistence.StoreRepository
import com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus
import com.sangdol.roomescape.theme.dto.ThemeCreateRequest
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository
import com.sangdol.roomescape.theme.dto.ThemeCreateRequest
import com.sangdol.roomescape.theme.mapper.toEntity
import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity
import org.springframework.data.repository.findByIdOrNull
@ -164,10 +159,10 @@ class DummyInitializer(
fun createPayment(
reservationId: Long,
request: PaymentConfirmRequest = PaymentFixture.confirmRequest,
cardDetail: CardDetail? = null,
easyPayDetail: EasyPayDetail? = null,
transferDetail: TransferDetail? = null,
): PaymentWithDetailResponse {
cardDetail: CardDetailResponse? = null,
easyPayDetail: EasyPayDetailResponse? = null,
transferDetail: TransferDetailResponse? = null,
): PaymentResponse {
val method = if (easyPayDetail != null) {
PaymentMethod.EASY_PAY
} else if (cardDetail != null) {
@ -190,12 +185,12 @@ class DummyInitializer(
val payment = paymentWriter.createPayment(
reservationId = reservationId,
paymentClientConfirmResponse = clientConfirmResponse
paymentGatewayResponse = clientConfirmResponse
)
val detail = paymentWriter.createDetail(clientConfirmResponse, payment.id)
return payment.toDetailResponse(detail = detail.toPaymentDetailResponse(), cancel = null)
return payment.toResponse(detail = detail.toResponse(), cancel = null)
}
fun cancelPayment(

View File

@ -6,10 +6,22 @@ import com.sangdol.common.utils.KoreaDateTime
import com.sangdol.roomescape.admin.infrastructure.persistence.AdminEntity
import com.sangdol.roomescape.admin.infrastructure.persistence.AdminPermissionLevel
import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType
import com.sangdol.roomescape.payment.infrastructure.client.*
import com.sangdol.roomescape.payment.infrastructure.common.*
import com.sangdol.roomescape.payment.web.PaymentCancelRequest
import com.sangdol.roomescape.payment.web.PaymentConfirmRequest
import com.sangdol.roomescape.payment.business.domain.BankCode
import com.sangdol.roomescape.payment.business.domain.CardIssuerCode
import com.sangdol.roomescape.payment.business.domain.CardOwnerType
import com.sangdol.roomescape.payment.business.domain.CardType
import com.sangdol.roomescape.payment.business.domain.EasyPayCompanyCode
import com.sangdol.roomescape.payment.business.domain.PaymentMethod
import com.sangdol.roomescape.payment.business.domain.PaymentStatus
import com.sangdol.roomescape.payment.business.domain.PaymentType
import com.sangdol.roomescape.payment.dto.CancelDetail
import com.sangdol.roomescape.payment.dto.CardDetailResponse
import com.sangdol.roomescape.payment.dto.EasyPayDetailResponse
import com.sangdol.roomescape.payment.dto.PaymentGatewayCancelResponse
import com.sangdol.roomescape.payment.dto.PaymentGatewayResponse
import com.sangdol.roomescape.payment.dto.TransferDetailResponse
import com.sangdol.roomescape.payment.dto.PaymentCancelRequest
import com.sangdol.roomescape.payment.dto.PaymentConfirmRequest
import com.sangdol.roomescape.reservation.dto.PendingReservationCreateRequest
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntity
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleEntityFactory
@ -254,7 +266,7 @@ object PaymentFixture {
cardType: CardType = CardType.entries.random(),
ownerType: CardOwnerType = CardOwnerType.entries.random(),
installmentPlanMonths: Int = 0,
): CardDetail = CardDetail(
): CardDetailResponse = CardDetailResponse(
issuerCode = issuerCode,
number = "${(400000..500000).random()}*********",
amount = amount,
@ -269,12 +281,12 @@ object PaymentFixture {
amount: Int,
provider: EasyPayCompanyCode = EasyPayCompanyCode.entries.random(),
discountAmount: Int = 0
): EasyPayDetail = EasyPayDetail(provider, amount, discountAmount)
): EasyPayDetailResponse = EasyPayDetailResponse(provider, amount, discountAmount)
fun transferDetail(
bankCode: BankCode = BankCode.entries.random(),
settlementStatus: String = "COMPLETED"
): TransferDetail = TransferDetail(
): TransferDetailResponse = TransferDetailResponse(
bankCode = bankCode,
settlementStatus = settlementStatus
)
@ -283,11 +295,11 @@ object PaymentFixture {
paymentKey: String,
amount: Int,
method: PaymentMethod,
cardDetail: CardDetail?,
easyPayDetail: EasyPayDetail?,
transferDetail: TransferDetail?,
cardDetail: CardDetailResponse?,
easyPayDetail: EasyPayDetailResponse?,
transferDetail: TransferDetailResponse?,
orderId: String = randomString(25),
) = PaymentClientConfirmResponse(
) = PaymentGatewayResponse(
paymentKey = paymentKey,
status = PaymentStatus.DONE,
orderId = orderId,
@ -309,7 +321,7 @@ object PaymentFixture {
transferDiscountAmount: Int = 0,
easypayDiscountAmount: Int = 0,
cancelReason: String = "cancelReason"
) = PaymentClientCancelResponse(
) = PaymentGatewayCancelResponse(
status = PaymentStatus.CANCELED,
cancels = CancelDetail(
cancelAmount = amount,