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.* import roomescape.auth.web.support.MemberId import roomescape.common.dto.response.CommonApiResponse import roomescape.common.exception.RoomescapeException import roomescape.payment.infrastructure.client.TossPaymentClient import roomescape.payment.web.PaymentApprove import roomescape.payment.web.PaymentCancel import roomescape.reservation.business.ReservationService import roomescape.reservation.business.ReservationWithPaymentService import roomescape.reservation.docs.ReservationAPI import java.net.URI import java.time.LocalDate @RestController class ReservationController( private val reservationWithPaymentService: ReservationWithPaymentService, private val reservationService: ReservationService, private val paymentClient: TossPaymentClient ) : ReservationAPI { @GetMapping("/reservations") override fun getAllReservations(): ResponseEntity> { val response: ReservationsResponse = reservationService.findAllReservations() return ResponseEntity.ok(CommonApiResponse(response)) } @GetMapping("/reservations-mine") override fun getMemberReservations( @MemberId @Parameter(hidden = true) memberId: Long ): ResponseEntity> { val response: MyReservationsResponse = reservationService.findMemberReservations(memberId) return ResponseEntity.ok(CommonApiResponse(response)) } @GetMapping("/reservations/search") override fun getReservationBySearching( @RequestParam(required = false) themeId: Long?, @RequestParam(required = false) memberId: Long?, @RequestParam(required = false) dateFrom: LocalDate?, @RequestParam(required = false) dateTo: LocalDate? ): ResponseEntity> { val response: ReservationsResponse = reservationService.findFilteredReservations(themeId, memberId, dateFrom, dateTo) return ResponseEntity.ok(CommonApiResponse(response)) } @DeleteMapping("/reservations/{id}") override fun removeReservation( @MemberId @Parameter(hidden = true) memberId: Long, @PathVariable("id") reservationId: Long ): ResponseEntity> { if (reservationWithPaymentService.isNotPaidReservation(reservationId)) { reservationService.removeReservationById(reservationId, memberId) return ResponseEntity.noContent().build() } val paymentCancelRequest = reservationWithPaymentService.removeReservationWithPayment( reservationId, memberId) val paymentCancelResponse = paymentClient.cancelPayment(paymentCancelRequest) reservationWithPaymentService.updateCanceledTime(paymentCancelRequest.paymentKey, paymentCancelResponse.canceledAt) return ResponseEntity.noContent().build() } @PostMapping("/reservations") override fun saveReservation( @Valid @RequestBody reservationRequest: ReservationRequest, @MemberId @Parameter(hidden = true) memberId: Long ): ResponseEntity> { val paymentRequest: PaymentApprove.Request = reservationRequest.paymentRequest val paymentResponse: PaymentApprove.Response = paymentClient.confirmPayment(paymentRequest) try { val reservationResponse: ReservationResponse = reservationWithPaymentService.addReservationWithPayment( reservationRequest, paymentResponse, memberId ) return ResponseEntity.created(URI.create("/reservations/${reservationResponse.id}")) .body(CommonApiResponse(reservationResponse)) } catch (e: RoomescapeException) { val cancelRequest = PaymentCancel.Request(paymentRequest.paymentKey, paymentRequest.amount, e.message!!) val paymentCancelResponse = paymentClient.cancelPayment(cancelRequest) reservationWithPaymentService.saveCanceledPayment(paymentCancelResponse, paymentResponse.approvedAt, paymentRequest.paymentKey) throw e } } @PostMapping("/reservations/admin") override fun saveReservationByAdmin( @Valid @RequestBody adminReservationRequest: AdminReservationRequest ): ResponseEntity> { val response: ReservationResponse = reservationService.addReservationByAdmin(adminReservationRequest) return ResponseEntity.created(URI.create("/reservations/${response.id}")) .body(CommonApiResponse(response)) } @GetMapping("/reservations/waiting") override fun getAllWaiting(): ResponseEntity> { val response: ReservationsResponse = reservationService.findAllWaiting() return ResponseEntity.ok(CommonApiResponse(response)) } @PostMapping("/reservations/waiting") override fun saveWaiting( @Valid @RequestBody waitingRequest: WaitingRequest, @MemberId @Parameter(hidden = true) memberId: Long, ): ResponseEntity> { val response: ReservationResponse = reservationService.addWaiting( waitingRequest, memberId ) return ResponseEntity.created(URI.create("/reservations/${response.id}")) .body(CommonApiResponse(response)) } @DeleteMapping("/reservations/waiting/{id}") override fun deleteWaiting( @MemberId @Parameter(hidden = true) memberId: Long, @PathVariable("id") reservationId: Long ): ResponseEntity> { reservationService.cancelWaiting(reservationId, memberId) return ResponseEntity.noContent().build() } @PostMapping("/reservations/waiting/{id}/approve") override fun approveWaiting( @MemberId @Parameter(hidden = true) memberId: Long, @PathVariable("id") reservationId: Long ): ResponseEntity> { reservationService.approveWaiting(reservationId, memberId) return ResponseEntity.ok().build() } @PostMapping("/reservations/waiting/{id}/deny") override fun denyWaiting( @MemberId @Parameter(hidden = true) memberId: Long, @PathVariable("id") reservationId: Long ): ResponseEntity> { reservationService.denyWaiting(reservationId, memberId) return ResponseEntity.noContent().build() } }