generated from pricelees/issue-pr-template
feat: 새로운 회원의 예약 조회 API 구현
This commit is contained in:
parent
ba324464e9
commit
110d91a31e
@ -0,0 +1,54 @@
|
||||
package roomescape.reservation.business
|
||||
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import roomescape.payment.implement.PaymentFinderV2
|
||||
import roomescape.payment.infrastructure.persistence.v2.CanceledPaymentEntityV2
|
||||
import roomescape.payment.infrastructure.persistence.v2.PaymentDetailEntity
|
||||
import roomescape.payment.infrastructure.persistence.v2.PaymentEntityV2
|
||||
import roomescape.reservation.implement.ReservationFinder
|
||||
import roomescape.reservation.infrastructure.persistence.ReservationEntity
|
||||
import roomescape.reservation.web.ReservationDetailRetrieveResponse
|
||||
import roomescape.reservation.web.ReservationSummaryRetrieveListResponse
|
||||
import roomescape.reservation.web.toCancelDetailResponse
|
||||
import roomescape.reservation.web.toPaymentDetailResponse
|
||||
import roomescape.reservation.web.toReservationDetailRetrieveResponse
|
||||
import roomescape.reservation.web.toRetrieveResponse
|
||||
import roomescape.reservation.web.toSummaryListResponse
|
||||
|
||||
private val log: KLogger = KotlinLogging.logger {}
|
||||
|
||||
@Service
|
||||
class MyReservationFindService(
|
||||
private val reservationFinder: ReservationFinder,
|
||||
private val paymentFinder: PaymentFinderV2
|
||||
) {
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun findReservationsByMemberId(memberId: Long): ReservationSummaryRetrieveListResponse {
|
||||
log.debug { "[ReservationFindServiceV2.findReservationsByMemberId] 시작: memberId=$memberId" }
|
||||
|
||||
return reservationFinder.findAllByMemberIdV2(memberId)
|
||||
.toSummaryListResponse()
|
||||
.also { log.info { "[ReservationFindServiceV2.findReservationsByMemberId] ${it.reservations.size}개의 예약 조회 완료: memberId=$memberId" } }
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun showReservationDetails(reservationId: Long): ReservationDetailRetrieveResponse {
|
||||
log.debug { "[ReservationFindServiceV2.showReservationDetails] 시작: reservationId=$reservationId" }
|
||||
|
||||
val reservation: ReservationEntity = reservationFinder.findById(reservationId)
|
||||
val payment: PaymentEntityV2 = paymentFinder.findPaymentByReservationId(reservationId)
|
||||
val paymentDetail: PaymentDetailEntity = paymentFinder.findPaymentDetailByPaymentId(payment.id)
|
||||
val canceledPayment: CanceledPaymentEntityV2? = paymentFinder.findCanceledPaymentByPaymentIdOrNull(payment.id)
|
||||
|
||||
return reservation.toReservationDetailRetrieveResponse(
|
||||
payment = payment.toRetrieveResponse(detail = paymentDetail.toPaymentDetailResponse()),
|
||||
cancellation = canceledPayment?.toCancelDetailResponse()
|
||||
).also {
|
||||
log.info { "[ReservationFindServiceV2.showReservationDetails] 예약 상세 조회 완료: reservationId=$reservationId" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
package roomescape.reservation.docs
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation
|
||||
import io.swagger.v3.oas.annotations.Parameter
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import roomescape.auth.web.support.LoginRequired
|
||||
import roomescape.auth.web.support.MemberId
|
||||
import roomescape.common.dto.response.CommonApiResponse
|
||||
import roomescape.reservation.web.ReservationDetailRetrieveResponse
|
||||
import roomescape.reservation.web.ReservationSummaryRetrieveListResponse
|
||||
|
||||
interface MyReservationAPI {
|
||||
@LoginRequired
|
||||
@Operation(summary = "내 예약 개요 조회", tags = ["로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(responseCode = "200", description = "성공"),
|
||||
)
|
||||
fun findAllMyReservations(
|
||||
@MemberId @Parameter(hidden = true) memberId: Long
|
||||
): ResponseEntity<CommonApiResponse<ReservationSummaryRetrieveListResponse>>
|
||||
|
||||
@LoginRequired
|
||||
@Operation(summary = "예약 상세 조회", tags = ["로그인이 필요한 API"])
|
||||
@ApiResponses(
|
||||
ApiResponse(responseCode = "200", description = "성공"),
|
||||
)
|
||||
fun showReservationDetails(
|
||||
@PathVariable("id") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<ReservationDetailRetrieveResponse>>
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
package roomescape.reservation.web
|
||||
|
||||
import io.swagger.v3.oas.annotations.Parameter
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.GetMapping
|
||||
import org.springframework.web.bind.annotation.PathVariable
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import roomescape.auth.web.support.MemberId
|
||||
import roomescape.common.dto.response.CommonApiResponse
|
||||
import roomescape.reservation.business.MyReservationFindService
|
||||
import roomescape.reservation.docs.MyReservationAPI
|
||||
|
||||
@RestController
|
||||
class MyReservationController(
|
||||
private val reservationFindService: MyReservationFindService
|
||||
) : MyReservationAPI {
|
||||
|
||||
@GetMapping("/v2/reservations")
|
||||
override fun findAllMyReservations(
|
||||
@MemberId @Parameter(hidden=true) memberId: Long
|
||||
): ResponseEntity<CommonApiResponse<ReservationSummaryRetrieveListResponse>> {
|
||||
val response = reservationFindService.findReservationsByMemberId(memberId)
|
||||
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
}
|
||||
|
||||
@GetMapping("/v2/reservations/{id}/details")
|
||||
override fun showReservationDetails(
|
||||
@PathVariable("id") reservationId: Long
|
||||
): ResponseEntity<CommonApiResponse<ReservationDetailRetrieveResponse>> {
|
||||
val response = reservationFindService.showReservationDetails(reservationId)
|
||||
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,196 @@
|
||||
package roomescape.reservation.web
|
||||
|
||||
import roomescape.member.infrastructure.persistence.MemberEntity
|
||||
import roomescape.payment.exception.PaymentErrorCode
|
||||
import roomescape.payment.exception.PaymentException
|
||||
import roomescape.payment.infrastructure.common.PaymentStatus
|
||||
import roomescape.payment.infrastructure.persistence.v2.CanceledPaymentEntityV2
|
||||
import roomescape.payment.infrastructure.persistence.v2.PaymentBankTransferDetailEntity
|
||||
import roomescape.payment.infrastructure.persistence.v2.PaymentCardDetailEntity
|
||||
import roomescape.payment.infrastructure.persistence.v2.PaymentDetailEntity
|
||||
import roomescape.payment.infrastructure.persistence.v2.PaymentEasypayPrepaidDetailEntity
|
||||
import roomescape.payment.infrastructure.persistence.v2.PaymentEntityV2
|
||||
import roomescape.reservation.infrastructure.persistence.ReservationEntity
|
||||
import roomescape.reservation.infrastructure.persistence.ReservationStatus
|
||||
import roomescape.reservation.web.PaymentDetailResponse.BankTransferDetailResponse
|
||||
import roomescape.reservation.web.PaymentDetailResponse.CardDetailResponse
|
||||
import roomescape.reservation.web.PaymentDetailResponse.EasyPayPrepaidDetailResponse
|
||||
import java.time.LocalDate
|
||||
import java.time.LocalDateTime
|
||||
import java.time.LocalTime
|
||||
import java.time.OffsetDateTime
|
||||
import kotlin.Int
|
||||
|
||||
data class ReservationSummaryRetrieveResponse(
|
||||
val id: Long,
|
||||
val themeName: String,
|
||||
val date: LocalDate,
|
||||
val startAt: LocalTime,
|
||||
val status: ReservationStatus
|
||||
)
|
||||
|
||||
fun ReservationEntity.toReservationSummaryRetrieveResponse(): ReservationSummaryRetrieveResponse {
|
||||
return ReservationSummaryRetrieveResponse(
|
||||
id = this.id!!,
|
||||
themeName = this.theme.name,
|
||||
date = this.date,
|
||||
startAt = this.time.startAt,
|
||||
status = this.status
|
||||
)
|
||||
}
|
||||
|
||||
data class ReservationSummaryRetrieveListResponse(
|
||||
val reservations: List<ReservationSummaryRetrieveResponse>
|
||||
)
|
||||
|
||||
fun List<ReservationEntity>.toSummaryListResponse(): ReservationSummaryRetrieveListResponse {
|
||||
return ReservationSummaryRetrieveListResponse(
|
||||
reservations = this.map { it.toReservationSummaryRetrieveResponse() }
|
||||
)
|
||||
}
|
||||
|
||||
data class ReservationDetailRetrieveResponse(
|
||||
val id: Long,
|
||||
val user: UserDetailRetrieveResponse,
|
||||
val themeName: String,
|
||||
val date: LocalDate,
|
||||
val startAt: LocalTime,
|
||||
val applicationDateTime: LocalDateTime,
|
||||
val payment: PaymentRetrieveResponse,
|
||||
val cancellation: PaymentCancelDetailResponse? = null
|
||||
)
|
||||
|
||||
data class UserDetailRetrieveResponse(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val email: String
|
||||
)
|
||||
|
||||
fun MemberEntity.toUserDetailRetrieveResponse(): UserDetailRetrieveResponse {
|
||||
return UserDetailRetrieveResponse(
|
||||
id = this.id!!,
|
||||
name = this.name,
|
||||
email = this.email
|
||||
)
|
||||
}
|
||||
|
||||
fun ReservationEntity.toReservationDetailRetrieveResponse(
|
||||
payment: PaymentRetrieveResponse,
|
||||
cancellation: PaymentCancelDetailResponse? = null
|
||||
): ReservationDetailRetrieveResponse {
|
||||
return ReservationDetailRetrieveResponse(
|
||||
id = this.id!!,
|
||||
user = this.member.toUserDetailRetrieveResponse(),
|
||||
themeName = this.theme.name,
|
||||
date = this.date,
|
||||
startAt = this.time.startAt,
|
||||
applicationDateTime = this.createdAt!!,
|
||||
payment = payment,
|
||||
cancellation = cancellation,
|
||||
)
|
||||
}
|
||||
|
||||
data class PaymentRetrieveResponse(
|
||||
val orderId: String,
|
||||
val totalAmount: Int,
|
||||
val method: String,
|
||||
val status: PaymentStatus,
|
||||
val requestedAt: OffsetDateTime,
|
||||
val approvedAt: OffsetDateTime,
|
||||
val detail: PaymentDetailResponse,
|
||||
)
|
||||
|
||||
fun PaymentEntityV2.toRetrieveResponse(detail: PaymentDetailResponse): PaymentRetrieveResponse {
|
||||
return PaymentRetrieveResponse(
|
||||
orderId = this.orderId,
|
||||
totalAmount = this.totalAmount,
|
||||
method = this.method.koreanName,
|
||||
status = this.status,
|
||||
requestedAt = this.requestedAt,
|
||||
approvedAt = this.approvedAt,
|
||||
detail = detail
|
||||
)
|
||||
}
|
||||
|
||||
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: LocalDateTime,
|
||||
val cancellationApprovedAt: OffsetDateTime?,
|
||||
val cancelReason: String,
|
||||
val canceledBy: Long,
|
||||
)
|
||||
|
||||
fun CanceledPaymentEntityV2.toCancelDetailResponse(): PaymentCancelDetailResponse {
|
||||
return PaymentCancelDetailResponse(
|
||||
cancellationRequestedAt = this.requestedAt,
|
||||
cancellationApprovedAt = this.canceledAt,
|
||||
cancelReason = this.cancelReason,
|
||||
canceledBy = this.canceledBy
|
||||
)
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user