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

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

View File

@ -1,6 +1,8 @@
package com.sangdol.roomescape.payment.business package com.sangdol.roomescape.payment.business
import com.sangdol.common.persistence.TransactionExecutionUtil import com.sangdol.common.persistence.TransactionExecutionUtil
import com.sangdol.roomescape.payment.business.domain.PaymentClientError
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
@ -24,25 +26,37 @@ class PaymentService(
private val paymentWriter: PaymentWriter, private val paymentWriter: PaymentWriter,
private val transactionExecutionUtil: TransactionExecutionUtil, private val transactionExecutionUtil: TransactionExecutionUtil,
) { ) {
fun confirm(reservationId: Long, request: PaymentConfirmRequest): PaymentCreateResponse { fun requestConfirm(request: PaymentConfirmRequest): PaymentClientConfirmResponse {
val clientConfirmResponse: PaymentClientConfirmResponse = paymentClient.confirm( try {
paymentKey = request.paymentKey, return paymentClient.confirm(request.paymentKey, request.orderId, request.amount)
orderId = request.orderId, } catch (e: ExternalPaymentException) {
amount = request.amount, val errorCode = if (e.httpStatusCode in 400..<500) {
) PaymentErrorCode.PAYMENT_CLIENT_ERROR
} else {
PaymentErrorCode.PAYMENT_PROVIDER_ERROR
}
return transactionExecutionUtil.withNewTransaction(isReadOnly = false) { val message = if (PaymentClientError.contains(e.errorCode)) {
"${errorCode.message}(${e.message})"
} else {
errorCode.message
}
throw PaymentException(errorCode, message)
}
}
fun savePayment(
reservationId: Long,
paymentConfirmResponse: PaymentClientConfirmResponse
): PaymentCreateResponse {
val payment: PaymentEntity = paymentWriter.createPayment( val payment: PaymentEntity = paymentWriter.createPayment(
reservationId = reservationId, reservationId = reservationId,
paymentClientConfirmResponse = clientConfirmResponse paymentClientConfirmResponse = paymentConfirmResponse
) )
val detail: PaymentDetailEntity = paymentWriter.createDetail(clientConfirmResponse, payment.id) val detail: PaymentDetailEntity = paymentWriter.createDetail(paymentConfirmResponse, payment.id)
PaymentCreateResponse(paymentId = payment.id, detailId = detail.id) return PaymentCreateResponse(paymentId = payment.id, detailId = detail.id)
} ?: run {
log.warn { "[confirm] 결제 확정 중 예상치 못한 null 반환" }
throw PaymentException(PaymentErrorCode.PAYMENT_UNEXPECTED_ERROR)
}
} }
fun cancel(userId: Long, request: PaymentCancelRequest) { fun cancel(userId: Long, request: PaymentCancelRequest) {

View File

@ -4,16 +4,15 @@ import com.sangdol.common.types.web.CommonApiResponse
import com.sangdol.roomescape.auth.web.support.User import com.sangdol.roomescape.auth.web.support.User
import com.sangdol.roomescape.auth.web.support.UserOnly import com.sangdol.roomescape.auth.web.support.UserOnly
import com.sangdol.roomescape.common.types.CurrentUserContext 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.PaymentCancelRequest
import com.sangdol.roomescape.payment.web.PaymentConfirmRequest import com.sangdol.roomescape.payment.web.PaymentConfirmRequest
import com.sangdol.roomescape.payment.web.PaymentCreateResponse
import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses import io.swagger.v3.oas.annotations.responses.ApiResponses
import jakarta.validation.Valid import jakarta.validation.Valid
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestParam
interface PaymentAPI { interface PaymentAPI {
@ -21,9 +20,8 @@ interface PaymentAPI {
@Operation(summary = "결제 승인") @Operation(summary = "결제 승인")
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true)) @ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
fun confirmPayment( fun confirmPayment(
@RequestParam(required = true) reservationId: Long,
@Valid @RequestBody request: PaymentConfirmRequest @Valid @RequestBody request: PaymentConfirmRequest
): ResponseEntity<CommonApiResponse<PaymentCreateResponse>> ): ResponseEntity<CommonApiResponse<PaymentClientConfirmResponse>>
@Operation(summary = "결제 취소") @Operation(summary = "결제 취소")
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true)) @ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))

View File

@ -5,6 +5,7 @@ import com.sangdol.roomescape.auth.web.support.User
import com.sangdol.roomescape.common.types.CurrentUserContext import com.sangdol.roomescape.common.types.CurrentUserContext
import com.sangdol.roomescape.payment.business.PaymentService import com.sangdol.roomescape.payment.business.PaymentService
import com.sangdol.roomescape.payment.docs.PaymentAPI import com.sangdol.roomescape.payment.docs.PaymentAPI
import com.sangdol.roomescape.payment.infrastructure.client.PaymentClientConfirmResponse
import jakarta.validation.Valid import jakarta.validation.Valid
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.* import org.springframework.web.bind.annotation.*
@ -15,12 +16,11 @@ class PaymentController(
private val paymentService: PaymentService private val paymentService: PaymentService
) : PaymentAPI { ) : PaymentAPI {
@PostMapping @PostMapping("/confirm")
override fun confirmPayment( override fun confirmPayment(
@RequestParam(required = true) reservationId: Long,
@Valid @RequestBody request: PaymentConfirmRequest @Valid @RequestBody request: PaymentConfirmRequest
): ResponseEntity<CommonApiResponse<PaymentCreateResponse>> { ): ResponseEntity<CommonApiResponse<PaymentClientConfirmResponse>> {
val response = paymentService.confirm(reservationId, request) val response = paymentService.requestConfirm(request)
return ResponseEntity.ok(CommonApiResponse(response)) return ResponseEntity.ok(CommonApiResponse(response))
} }