From 6eecd145cc6e85097e8ee92d64c0589c96d26c68 Mon Sep 17 00:00:00 2001 From: pricelees Date: Sat, 13 Sep 2025 15:40:36 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EA=B0=80=EC=9E=A5=20=EB=A7=8E=EC=9D=B4?= =?UTF-8?q?=20=EC=98=88=EC=95=BD=EB=90=9C=20=ED=85=8C=EB=A7=88=20ID=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../business/ReservationService.kt | 19 +++++++++++++++++++ .../reservation/docs/ReservationAPI.kt | 9 +++++++++ .../persistence/ReservationRepository.kt | 19 +++++++++++++++++++ .../reservation/web/ReservationController.kt | 9 +++++++++ .../reservation/web/ReservationDto.kt | 6 +++++- 5 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/main/kotlin/roomescape/reservation/business/ReservationService.kt b/src/main/kotlin/roomescape/reservation/business/ReservationService.kt index e7d20335..653317a7 100644 --- a/src/main/kotlin/roomescape/reservation/business/ReservationService.kt +++ b/src/main/kotlin/roomescape/reservation/business/ReservationService.kt @@ -9,6 +9,7 @@ import org.springframework.transaction.annotation.Transactional import roomescape.common.config.next import roomescape.common.dto.CurrentUserContext import roomescape.common.dto.PrincipalType +import roomescape.common.util.DateUtils import roomescape.member.business.UserService import roomescape.member.web.UserContactRetrieveResponse import roomescape.payment.business.PaymentService @@ -23,6 +24,7 @@ import roomescape.schedule.web.ScheduleSummaryResponse import roomescape.schedule.web.ScheduleUpdateRequest import roomescape.theme.business.ThemeService import roomescape.theme.web.ThemeInfoRetrieveResponse +import java.time.LocalDate import java.time.LocalDateTime private val log: KLogger = KotlinLogging.logger {} @@ -126,6 +128,23 @@ class ReservationService( } } + @Transactional(readOnly = true) + fun findMostReservedThemeIds(count: Int): MostReservedThemeIdListResponse { + log.info { "[ReservationService.findMostReservedThemeIds] 인기 테마 조회 시작: count=$count" } + val previousWeekSunday = DateUtils.getSundayOfPreviousWeek(LocalDate.now()) + val previousWeekSaturday = previousWeekSunday.plusDays(6) + + val themeIds: List = reservationRepository.findMostReservedThemeIds( + dateFrom = previousWeekSunday, + dateTo = previousWeekSaturday, + count = count + ) + + return MostReservedThemeIdListResponse(themeIds = themeIds).also { + log.info { "[ReservationService.findMostReservedThemeIds] 인기 테마 조회 완료: count=${it.themeIds.size}" } + } + } + private fun findOrThrow(id: Long): ReservationEntity { log.info { "[ReservationService.findOrThrow] 예약 조회 시작: reservationId=${id}" } diff --git a/src/main/kotlin/roomescape/reservation/docs/ReservationAPI.kt b/src/main/kotlin/roomescape/reservation/docs/ReservationAPI.kt index 262f7329..ba331c45 100644 --- a/src/main/kotlin/roomescape/reservation/docs/ReservationAPI.kt +++ b/src/main/kotlin/roomescape/reservation/docs/ReservationAPI.kt @@ -7,8 +7,10 @@ import jakarta.validation.Valid import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestParam import roomescape.auth.web.support.Authenticated import roomescape.auth.web.support.CurrentUser +import roomescape.auth.web.support.Public import roomescape.auth.web.support.UserOnly import roomescape.common.dto.CurrentUserContext import roomescape.common.dto.response.CommonApiResponse @@ -16,6 +18,13 @@ import roomescape.reservation.web.* interface ReservationAPI { + @Public + @Operation(summary = "결제 대기 예약 저장", tags = ["로그인이 필요한 API"]) + @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) + fun findMostReservedThemeIds( + @RequestParam count: Int + ): ResponseEntity> + @UserOnly @Operation(summary = "결제 대기 예약 저장", tags = ["로그인이 필요한 API"]) @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) diff --git a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt b/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt index aba5f37f..d3417f45 100644 --- a/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt +++ b/src/main/kotlin/roomescape/reservation/infrastructure/persistence/ReservationRepository.kt @@ -1,8 +1,27 @@ package roomescape.reservation.infrastructure.persistence import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.data.jpa.repository.Query +import org.springframework.data.repository.query.Param +import java.time.LocalDate interface ReservationRepository : JpaRepository { fun findAllByUserId(userId: Long): List + + @Query(""" + SELECT s.themeId + FROM ReservationEntity r + JOIN ScheduleEntity s ON s._id = r.scheduleId + WHERE r.status = roomescape.reservation.infrastructure.persistence.ReservationStatus.CONFIRMED + AND s.date BETWEEN :dateFrom AND :dateTo + GROUP BY s.themeId + ORDER BY count(r) DESC + LIMIT :count + """) + fun findMostReservedThemeIds( + @Param("dateFrom") dateFrom: LocalDate, + @Param("dateTo") dateTo: LocalDate, + @Param("count") count: Int + ): List } diff --git a/src/main/kotlin/roomescape/reservation/web/ReservationController.kt b/src/main/kotlin/roomescape/reservation/web/ReservationController.kt index ae0652cb..5ef79e71 100644 --- a/src/main/kotlin/roomescape/reservation/web/ReservationController.kt +++ b/src/main/kotlin/roomescape/reservation/web/ReservationController.kt @@ -14,6 +14,15 @@ class ReservationController( private val reservationService: ReservationService ) : ReservationAPI { + @GetMapping("/reservations/popular-themes") + override fun findMostReservedThemeIds( + @RequestParam count: Int + ): ResponseEntity> { + val response = reservationService.findMostReservedThemeIds(count) + + return ResponseEntity.ok(CommonApiResponse(response)) + } + @PostMapping("/reservations/pending") override fun createPendingReservation( @CurrentUser user: CurrentUserContext, diff --git a/src/main/kotlin/roomescape/reservation/web/ReservationDto.kt b/src/main/kotlin/roomescape/reservation/web/ReservationDto.kt index beeadf1f..c7f6ff92 100644 --- a/src/main/kotlin/roomescape/reservation/web/ReservationDto.kt +++ b/src/main/kotlin/roomescape/reservation/web/ReservationDto.kt @@ -67,4 +67,8 @@ fun ReservationEntity.toReservationDetailRetrieveResponse( data class ReservationCancelRequest( val cancelReason: String -) \ No newline at end of file +) + +data class MostReservedThemeIdListResponse( + val themeIds: List +)