[#35] 결제 스키마 재정의 & 예약 조회 페이지 개선 #36

Merged
pricelees merged 37 commits from refactor/#35 into main 2025-08-22 06:43:16 +00:00
3 changed files with 176 additions and 0 deletions
Showing only changes of commit 4d98b18016 - Show all commits

View File

@ -0,0 +1,61 @@
package roomescape.reservation.docs
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.headers.Header
import io.swagger.v3.oas.annotations.media.Schema
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import jakarta.validation.Valid
import org.springframework.http.HttpHeaders
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestBody
import roomescape.auth.web.support.LoginRequired
import roomescape.auth.web.support.MemberId
import roomescape.common.dto.response.CommonApiResponse
import roomescape.reservation.web.*
interface ReservationWithPaymentAPI {
@LoginRequired
@Operation(summary = "예약 추가", tags = ["로그인이 필요한 API"])
@ApiResponses(
ApiResponse(
responseCode = "200",
description = "성공",
useReturnTypeSchema = true,
headers = [Header(
name = HttpHeaders.LOCATION,
description = "생성된 예약 정보 URL",
schema = Schema(example = "/reservations/1")
)]
)
)
fun createPendingReservation(
@MemberId @Parameter(hidden = true) memberId: Long,
@Valid @RequestBody reservationCreateWithPaymentRequest: ReservationCreateRequest
): ResponseEntity<CommonApiResponse<ReservationCreateResponseV2>>
@LoginRequired
@Operation(summary = "예약 취소", tags = ["로그인이 필요한 API"])
@ApiResponses(
ApiResponse(responseCode = "204", description = "성공"),
)
fun cancelReservation(
@MemberId @Parameter(hidden = true) memberId: Long,
@PathVariable("id") reservationId: Long,
@Valid @RequestBody cancelRequest: ReservationCancelRequest
): ResponseEntity<CommonApiResponse<Unit>>
@LoginRequired
@Operation(summary = "예약 결제", tags = ["로그인이 필요한 API"])
@ApiResponses(
ApiResponse(responseCode = "200", description = "성공"),
)
fun createPaymentAndConfirmReservation(
@MemberId @Parameter(hidden = true) memberId: Long,
@PathVariable("id") reservationId: Long,
@Valid @RequestBody request: ReservationPaymentRequest
): ResponseEntity<CommonApiResponse<ReservationPaymentResponse>>
}

View File

@ -0,0 +1,60 @@
package roomescape.reservation.web
import io.swagger.v3.oas.annotations.Parameter
import jakarta.validation.Valid
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PatchMapping
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController
import roomescape.auth.web.support.MemberId
import roomescape.common.dto.response.CommonApiResponse
import roomescape.reservation.business.ReservationWithPaymentService
import roomescape.reservation.business.ReservationWithPaymentServiceV2
import roomescape.reservation.docs.ReservationWithPaymentAPI
@RestController
class ReservationWithPaymentController(
private val reservationWithPaymentService: ReservationWithPaymentServiceV2
) : ReservationWithPaymentAPI {
@PostMapping("/v2/reservations")
override fun createPendingReservation(
@MemberId @Parameter(hidden = true) memberId: Long,
@Valid @RequestBody reservationCreateWithPaymentRequest: ReservationCreateRequest
): ResponseEntity<CommonApiResponse<ReservationCreateResponseV2>> {
val response = reservationWithPaymentService.createPendingReservation(
memberId = memberId,
request = reservationCreateWithPaymentRequest
)
return ResponseEntity.ok(CommonApiResponse(response))
}
@PostMapping("/v2/reservations/{id}/pay")
override fun createPaymentAndConfirmReservation(
@MemberId @Parameter(hidden = true) memberId: Long,
@PathVariable("id") reservationId: Long,
@Valid @RequestBody request: ReservationPaymentRequest,
): ResponseEntity<CommonApiResponse<ReservationPaymentResponse>> {
val response = reservationWithPaymentService.payReservation(
memberId = memberId,
reservationId = reservationId,
request = request
)
return ResponseEntity.ok(CommonApiResponse(response))
}
@PostMapping("/v2/reservations/{id}/cancel")
override fun cancelReservation(
@MemberId @Parameter(hidden = true) memberId: Long,
@PathVariable("id") reservationId: Long,
@Valid @RequestBody cancelRequest: ReservationCancelRequest
): ResponseEntity<CommonApiResponse<Unit>> {
reservationWithPaymentService.cancelReservation(memberId, reservationId, cancelRequest)
return ResponseEntity.noContent().build()
}
}

View File

@ -0,0 +1,55 @@
package roomescape.reservation.web
import roomescape.payment.infrastructure.client.v2.PaymentConfirmRequest
import roomescape.payment.infrastructure.common.PaymentStatus
import roomescape.payment.infrastructure.common.PaymentType
import roomescape.reservation.infrastructure.persistence.ReservationEntity
import roomescape.reservation.infrastructure.persistence.ReservationStatus
import java.time.LocalDate
import java.time.LocalTime
data class ReservationCreateRequest(
val date: LocalDate,
val timeId: Long,
val themeId: Long,
)
data class ReservationCreateResponseV2(
val reservationId: Long,
val memberEmail: String,
val date: LocalDate,
val startAt: LocalTime,
val themeName: String
)
fun ReservationEntity.toCreateResponseV2() = ReservationCreateResponseV2(
reservationId = this.id!!,
memberEmail = this.member.email,
date = this.date,
startAt = this.time.startAt,
themeName = this.theme.name
)
data class ReservationPaymentRequest(
val paymentKey: String,
val orderId: String,
val amount: Long,
val paymentType: PaymentType
)
fun ReservationPaymentRequest.toPaymentConfirmRequest() = PaymentConfirmRequest(
paymentKey = this.paymentKey,
amount = this.amount,
orderId = this.orderId,
)
data class ReservationPaymentResponse(
val reservationId: Long,
val reservationStatus: ReservationStatus,
val paymentId: Long,
val paymentStatus: PaymentStatus,
)
data class ReservationCancelRequest(
val cancelReason: String
)