Skip to content

Commit 549079a

Browse files
committed
feat(#102): 대여 기록 추가/삭제 API 구현
1 parent 2855f60 commit 549079a

File tree

4 files changed

+101
-10
lines changed

4 files changed

+101
-10
lines changed

src/main/kotlin/site/billilge/api/backend/domain/rental/controller/AdminRentalController.kt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package site.billilge.api.backend.domain.rental.controller
33
import org.springframework.http.ResponseEntity
44
import org.springframework.security.core.annotation.AuthenticationPrincipal
55
import org.springframework.web.bind.annotation.*
6+
import site.billilge.api.backend.domain.rental.dto.request.AdminRentalHistoryRequest
7+
import site.billilge.api.backend.domain.rental.dto.request.RentalHistoryRequest
68
import site.billilge.api.backend.domain.rental.dto.request.RentalStatusUpdateRequest
79
import site.billilge.api.backend.domain.rental.dto.response.AdminRentalHistoryFindAllResponse
810
import site.billilge.api.backend.domain.rental.dto.response.DashboardResponse
@@ -43,4 +45,18 @@ class AdminRentalController(
4345
rentalService.updateRentalStatus(userAuthInfo.memberId, rentalHistoryId, request)
4446
return ResponseEntity.ok().build()
4547
}
48+
49+
@PostMapping
50+
fun addRentalHistory(
51+
@RequestBody request: AdminRentalHistoryRequest
52+
): ResponseEntity<Void> {
53+
rentalService.createRentalByAdmin(request)
54+
return ResponseEntity.ok().build()
55+
}
56+
57+
@DeleteMapping("/{rentalHistoryId}")
58+
fun deleteRentalHistory(@PathVariable rentalHistoryId: Long): ResponseEntity<Void> {
59+
rentalService.deleteRentalHistory(rentalHistoryId)
60+
return ResponseEntity.ok().build()
61+
}
4662
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package site.billilge.api.backend.domain.rental.dto.request
2+
3+
import io.swagger.v3.oas.annotations.media.Schema
4+
5+
@Schema(description = "관리자 전용 대여기록 추가 DTO")
6+
data class AdminRentalHistoryRequest(
7+
@field:Schema(description = "대여자 ID", example = "1")
8+
val memberId: Long,
9+
10+
@field:Schema(description = "대여할 물품의 ID", example = "1")
11+
val itemId: Long,
12+
13+
@field:Schema(description = "대여할 물품의 수량", example = "1")
14+
val count: Int,
15+
16+
@field:Schema(description = "대여 시작 시간 정보")
17+
val rentalTime: RentalTime
18+
) {
19+
@Schema(description = "대여 시작 시간 (시간 및 분)")
20+
data class RentalTime(
21+
@field:Schema(description = "대여 시작 시각의 시간(24시간 기준)", example = "13")
22+
val hour: Int,
23+
24+
@field:Schema(description = "대여 시작 시각의 분", example = "0")
25+
val minute: Int
26+
)
27+
}

src/main/kotlin/site/billilge/api/backend/domain/rental/service/RentalService.kt

Lines changed: 57 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import site.billilge.api.backend.domain.member.exception.MemberErrorCode
1313
import site.billilge.api.backend.domain.member.repository.MemberRepository
1414
import site.billilge.api.backend.domain.notification.enums.NotificationStatus
1515
import site.billilge.api.backend.domain.notification.service.NotificationService
16+
import site.billilge.api.backend.domain.rental.dto.request.AdminRentalHistoryRequest
1617
import site.billilge.api.backend.domain.rental.dto.request.RentalHistoryRequest
1718
import site.billilge.api.backend.domain.rental.dto.request.RentalStatusUpdateRequest
1819
import site.billilge.api.backend.domain.rental.dto.response.*
@@ -129,16 +130,63 @@ class RentalService(
129130
true
130131
)
131132

132-
notificationService.sendNotificationToAdmin(
133-
NotificationStatus.ADMIN_RENTAL_APPLY,
134-
listOf(
135-
rentUser.name,
136-
rentUser.studentId,
137-
"${String.format("%02d", rentalHour)}:${String.format("%02d", rentalMinute)}",
138-
item.name
139-
),
140-
true
133+
if (!isDevMode) {
134+
notificationService.sendNotificationToAdmin(
135+
NotificationStatus.ADMIN_RENTAL_APPLY,
136+
listOf(
137+
rentUser.name,
138+
rentUser.studentId,
139+
"${String.format("%02d", rentalHour)}:${String.format("%02d", rentalMinute)}",
140+
item.name
141+
),
142+
true
143+
)
144+
}
145+
}
146+
147+
@Transactional
148+
fun createRentalByAdmin(request: AdminRentalHistoryRequest) {
149+
150+
val item = itemRepository.findById(request.itemId)
151+
.orElseThrow { ApiException(RentalErrorCode.ITEM_NOT_FOUND) }
152+
val rentedCount = request.count
153+
154+
if (rentedCount > item.count)
155+
throw ApiException(RentalErrorCode.ITEM_OUT_OF_STOCK)
156+
157+
val rentUser = memberRepository.findById(request.memberId)
158+
.orElseThrow { ApiException(RentalErrorCode.MEMBER_NOT_FOUND) }
159+
160+
if (!rentUser.isFeePaid)
161+
throw ApiException(RentalErrorCode.MEMBER_IS_NOT_PAYER)
162+
163+
val koreanZone = ZoneId.of("Asia/Seoul")
164+
val today = LocalDate.now(koreanZone)
165+
val requestedRentalDateTime = LocalDateTime.of(
166+
today,
167+
LocalTime.of(request.rentalTime.hour, request.rentalTime.minute)
141168
)
169+
170+
val rentAt = requestedRentalDateTime.atZone(koreanZone).toLocalDateTime()
171+
172+
val newRental = RentalHistory(
173+
member = rentUser,
174+
item = item,
175+
rentalStatus = if (item.type == ItemType.RENTAL) RentalStatus.RENTAL else RentalStatus.RETURNED,
176+
rentedCount = rentedCount,
177+
rentAt = rentAt
178+
).apply {
179+
if (rentalStatus == RentalStatus.RETURNED) {
180+
returnedAt = LocalDateTime.now()
181+
}
182+
}
183+
184+
rentalRepository.save(newRental)
185+
}
186+
187+
@Transactional
188+
fun deleteRentalHistory(rentalHistoryId: Long) {
189+
rentalRepository.deleteById(rentalHistoryId)
142190
}
143191

144192
fun getMemberRentalHistory(memberId: Long?, rentalStatus: RentalStatus?): RentalHistoryFindAllResponse {

src/main/kotlin/site/billilge/api/backend/global/config/SecurityConfig.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ class SecurityConfig (
7474
fun apiConfigurationSource(): CorsConfigurationSource {
7575
val configuration = CorsConfiguration()
7676
configuration.allowedOrigins = allowedOrigins.toList()
77-
configuration.allowedMethods = mutableListOf("GET", "POST", "PATCH", "PUT", "DELETE")
77+
configuration.allowedMethods = mutableListOf("GET", "POST", "PATCH", "PUT", "DELETE", "OPTIONS", "HEAD")
7878
configuration.allowedHeaders = mutableListOf("Content-Type", "Authorization")
7979

8080
val source = UrlBasedCorsConfigurationSource()

0 commit comments

Comments
 (0)