Skip to content

Commit 6d44361

Browse files
authored
Merge pull request #90 from Dalguring/feature/modify-rental
feature: 대여 요청, 취소, 대여내역 조회 API 리턴 json key값 변경 및 추가
2 parents 34f3c0a + 465bed3 commit 6d44361

5 files changed

Lines changed: 152 additions & 83 deletions

File tree

src/main/java/com/rentify/rentify_api/rental/controller/RentalApiDocs.java

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -38,22 +38,29 @@ public interface RentalApiDocs {
3838
examples = @ExampleObject(
3939
value = """
4040
{
41-
"success": true,
42-
"code": "SUCCESS",
43-
"message": "요청이 성공적으로 처리되었습니다.",
44-
"data": {
45-
"rentalId": 1,
46-
"userId": 1,
47-
"postId": 5,
48-
"startDate": "2026-02-10",
49-
"endDate": "2026-02-15",
50-
"receiveMethod": "PARCEL",
51-
"status": "REQUESTED",
52-
"totalPrice": 250000,
53-
"createdAt": "2026-02-08T10:30:00",
54-
"updatedAt": "2026-02-08T10:30:00"
55-
}
56-
}
41+
"success": true,
42+
"code": "201",
43+
"message": "요청이 성공적으로 처리되었습니다.",
44+
"data": {
45+
"canCancel": false,
46+
"canPay": true,
47+
"createdAt": "2026-03-26T09:38:43.976371",
48+
"endDate": "2026-05-15",
49+
"lenderName": "서성민굴",
50+
"paymentId": null,
51+
"postId": 13,
52+
"postStatus": "AVAILABLE",
53+
"receiveMethod": "PARCEL",
54+
"rentalId": 48,
55+
"rentalStatus": "REQUESTED",
56+
"startDate": "2026-05-10",
57+
"thumbnailUrl": "http://unirental.duckdns.org/images/885bf9e2-3440-4c22-a6b7-138bd24bb27c.jpg",
58+
"title": "갤럭시 s25 울트라 테스트121",
59+
"totalPrice": 210000,
60+
"updatedAt": "2026-03-26T09:38:43.976371",
61+
"userId": 13
62+
}
63+
}
5764
"""
5865
)
5966
)
Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,67 @@
11
package com.rentify.rentify_api.rental.dto;
22

3+
import com.rentify.rentify_api.payment.entity.Payment;
4+
import com.rentify.rentify_api.payment.entity.PaymentStatus;
5+
import com.rentify.rentify_api.post.entity.PostStatus;
36
import com.rentify.rentify_api.rental.entity.ReceiveMethod;
47
import com.rentify.rentify_api.rental.entity.Rental;
58
import com.rentify.rentify_api.rental.entity.RentalStatus;
9+
import java.time.LocalDate;
10+
import java.time.LocalDateTime;
11+
import lombok.AccessLevel;
612
import lombok.AllArgsConstructor;
713
import lombok.Builder;
814
import lombok.Getter;
915
import lombok.NoArgsConstructor;
1016

11-
import java.time.LocalDate;
12-
import java.time.LocalDateTime;
13-
1417
@Getter
15-
@NoArgsConstructor
16-
@AllArgsConstructor
18+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
19+
@AllArgsConstructor(access = AccessLevel.PRIVATE)
1720
@Builder
1821
public class RentalResponse {
1922

2023
private Long rentalId;
2124
private Long userId;
2225
private Long postId;
23-
private String lenderName; // 게시글작성자
24-
// private String borrowerName; // 대여자
26+
private Long paymentId;
27+
private String lenderName;
2528
private String title;
2629
private LocalDate startDate;
2730
private LocalDate endDate;
2831
private ReceiveMethod receiveMethod;
29-
private RentalStatus status;
32+
private PostStatus postStatus;
33+
private RentalStatus rentalStatus;
3034
private String thumbnailUrl;
3135
private Integer totalPrice;
36+
private boolean canPay;
37+
private boolean canCancel;
3238
private LocalDateTime createdAt;
3339
private LocalDateTime updatedAt;
3440

35-
public static RentalResponse from(Rental rental) {
41+
public static RentalResponse of(Rental rental, Payment payment) {
42+
boolean canPay = (payment == null || payment.getStatus() == PaymentStatus.FAILED)
43+
&& (rental.getStatus() == RentalStatus.REQUESTED);
44+
boolean canCancel = (payment != null && payment.getStatus() == PaymentStatus.PAID)
45+
&& (rental.getStatus() == RentalStatus.REQUESTED || rental.getStatus() == RentalStatus.CONFIRMED);
46+
3647
return RentalResponse.builder()
37-
.rentalId(rental.getId())
38-
.userId(rental.getUser().getId())
39-
//.borrowerName(rental.getUser().getName())
40-
.lenderName(rental.getPost().getUser().getName())
41-
.postId(rental.getPost().getId())
42-
.title(rental.getPost().getTitle()) // Post 제목
43-
.startDate(rental.getStartDate())
44-
.endDate(rental.getEndDate())
45-
.receiveMethod(rental.getReceiveMethod())
46-
.status(rental.getStatus())
47-
.thumbnailUrl(rental.getPost().getThumbnailUrl())
48-
.totalPrice(rental.getTotalPrice())
49-
.createdAt(rental.getCreatedAt())
50-
.updatedAt(rental.getUpdatedAt())
51-
.build();
48+
.rentalId(rental.getId())
49+
.userId(rental.getUser().getId())
50+
.paymentId(payment != null ? payment.getId() : null)
51+
.lenderName(rental.getPost().getUser().getName())
52+
.postId(rental.getPost().getId())
53+
.title(rental.getPost().getTitle())
54+
.startDate(rental.getStartDate())
55+
.endDate(rental.getEndDate())
56+
.receiveMethod(rental.getReceiveMethod())
57+
.postStatus(rental.getPost().getStatus())
58+
.rentalStatus(rental.getStatus())
59+
.thumbnailUrl(rental.getPost().getThumbnailUrl())
60+
.totalPrice(rental.getTotalPrice())
61+
.canPay(canPay)
62+
.canCancel(canCancel)
63+
.createdAt(rental.getCreatedAt())
64+
.updatedAt(rental.getUpdatedAt())
65+
.build();
5266
}
5367
}

src/main/java/com/rentify/rentify_api/rental/repository/RentalRepository.java

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.rentify.rentify_api.rental.repository;
22

3-
import com.rentify.rentify_api.rental.dto.RentalResponse;
43
import com.rentify.rentify_api.rental.entity.Rental;
54
import com.rentify.rentify_api.rental.entity.RentalStatus;
65
import jakarta.persistence.LockModeType;
@@ -32,31 +31,40 @@ List<Rental> findOverlappingRentals(
3231

3332
// 내가 빌린 대여 목록
3433
@Query(
35-
value = "SELECT r FROM Rental r " +
36-
"JOIN FETCH r.post p " +
37-
"JOIN FETCH p.user u " +
38-
"WHERE r.user.id = :userId " +
39-
"ORDER BY r.createdAt DESC ",
40-
countQuery = "SELECT count(r) FROM Rental r WHERE r.user.id = :userId"
41-
) Page<RentalResponse> findByUserId(@Param("userId") Long userId, Pageable pageable);
34+
value = "SELECT r, p FROM Rental r " +
35+
"JOIN FETCH r.post po " +
36+
"JOIN FETCH po.user u " +
37+
"LEFT JOIN Payment p ON p.rental = r " +
38+
"AND p.id = (SELECT MAX(p2.id) FROM Payment p2 WHERE p2.rental = r) " +
39+
"WHERE r.user.id = :userId " +
40+
"ORDER BY r.createdAt DESC ",
41+
countQuery = "SELECT count(r) FROM Rental r WHERE r.user.id = :userId"
42+
)
43+
Page<Object[]> findByUserId(@Param("userId") Long userId, Pageable pageable);
4244

4345
// 내가 빌려준 대여 목록
4446
@Query(
45-
value = "SELECT r FROM Rental r " +
46-
"JOIN FETCH r.post p " +
47-
"JOIN FETCH p.user u " +
48-
"WHERE p.user.id = :userId " +
49-
"ORDER BY r.createdAt DESC ",
50-
countQuery = "SELECT count(r) FROM Rental r JOIN r.post p WHERE p.user.id = :userId"
51-
) Page<RentalResponse> findByPostOwnerId(@Param("userId") Long userId, Pageable pageable);
47+
value = "SELECT r, p FROM Rental r " +
48+
"JOIN FETCH r.post po " +
49+
"JOIN FETCH po.user u " +
50+
"LEFT JOIN Payment p ON p.rental = r " +
51+
"AND p.id = (SELECT MAX(p2.id) FROM Payment p2 WHERE p2.rental = r) " +
52+
"WHERE po.user.id = :userId " +
53+
"ORDER BY r.createdAt DESC ",
54+
countQuery = "SELECT count(r) FROM Rental r JOIN r.post po WHERE po.user.id = :userId"
55+
)
56+
Page<Object[]> findByPostOwnerId(@Param("userId") Long userId, Pageable pageable);
5257

5358
// 나의 모든 대여 목록
5459
@Query(
55-
value = "SELECT r FROM Rental r " +
56-
"JOIN FETCH r.post p " +
57-
"JOIN FETCH p.user u " +
58-
"WHERE r.user.id = :userId OR p.user.id = :userId " +
59-
"ORDER BY r.createdAt DESC ",
60-
countQuery = "SELECT count(r) FROM Rental r JOIN r.post p WHERE r.user.id = :userId OR p.user.id = :userId"
61-
) Page<RentalResponse> findByUserIdOrPostOwnerId(@Param("userId") Long userId, Pageable pageable);
60+
value = "SELECT r, p FROM Rental r " +
61+
"JOIN FETCH r.post po " +
62+
"JOIN FETCH po.user u " +
63+
"LEFT JOIN Payment p ON p.rental = r " +
64+
"AND p.id = (SELECT MAX(p2.id) FROM Payment p2 WHERE p2.rental = r) " +
65+
"WHERE r.user.id = :userId OR po.user.id = :userId " +
66+
"ORDER BY r.createdAt DESC ",
67+
countQuery = "SELECT count(r) FROM Rental r JOIN r.post po WHERE r.user.id = :userId OR po.user.id = :userId"
68+
)
69+
Page<Object[]> findByUserIdOrPostOwnerId(@Param("userId") Long userId, Pageable pageable);
6270
}

src/main/java/com/rentify/rentify_api/rental/service/RentalService.java

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.rentify.rentify_api.rental.service;
22

33
import com.rentify.rentify_api.common.exception.NotFoundException;
4+
import com.rentify.rentify_api.payment.entity.Payment;
45
import com.rentify.rentify_api.post.entity.Post;
56
import com.rentify.rentify_api.post.entity.PostStatus;
67
import com.rentify.rentify_api.post.repository.PostRepository;
@@ -134,11 +135,16 @@ private static RentalResponse convertToResponse(Rental rental) {
134135
.rentalId(rental.getId())
135136
.userId(rental.getUser().getId())
136137
.postId(rental.getPost().getId())
138+
.postStatus(rental.getPost().getStatus())
139+
.lenderName(rental.getPost().getUser().getName())
140+
.thumbnailUrl(rental.getPost().getThumbnailUrl())
141+
.title(rental.getPost().getTitle())
137142
.startDate(rental.getStartDate())
138143
.endDate(rental.getEndDate())
139144
.receiveMethod(rental.getReceiveMethod())
140-
.status(rental.getStatus())
145+
.rentalStatus(rental.getStatus())
141146
.totalPrice(rental.getTotalPrice())
147+
.canPay(true)
142148
.createdAt(rental.getCreatedAt())
143149
.updatedAt(rental.getUpdatedAt())
144150
.build();
@@ -169,18 +175,30 @@ public RentalResponse cancelRental(Long userId, Long rentalId) {
169175
// 내가 빌리는 대여 목록
170176
@Transactional(readOnly = true)
171177
public Page<RentalResponse> getMyBorrowedRentals(Long userId, Pageable pageable) {
172-
return rentalRepository.findByUserId(userId, pageable);
178+
Page<Object[]> page = rentalRepository.findByUserId(userId, pageable);
179+
return mapToRentalResponsePage(page);
173180
}
174181

175182
// 내가 빌려준 대여 목록
176183
@Transactional(readOnly = true)
177184
public Page<RentalResponse> getMyLentRentals(Long userId, Pageable pageable) {
178-
return rentalRepository.findByPostOwnerId(userId, pageable);
185+
Page<Object[]> page = rentalRepository.findByPostOwnerId(userId, pageable);
186+
return mapToRentalResponsePage(page);
179187
}
180188

181189
// 나의 모든 대여 목록
182190
@Transactional(readOnly = true)
183191
public Page<RentalResponse> getMyAllRentals(Long userId, Pageable pageable) {
184-
return rentalRepository.findByUserIdOrPostOwnerId(userId, pageable);
192+
Page<Object[]> page = rentalRepository.findByUserIdOrPostOwnerId(userId, pageable);
193+
return mapToRentalResponsePage(page);
194+
}
195+
196+
private Page<RentalResponse> mapToRentalResponsePage(Page<Object[]> results) {
197+
return results.map(row -> {
198+
Rental rental = (Rental) row[0];
199+
Payment payment = (Payment) row[1];
200+
201+
return RentalResponse.of(rental, payment);
202+
});
185203
}
186204
}

src/main/java/com/rentify/rentify_api/user/controller/UserApiDocs.java

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -363,33 +363,55 @@ ResponseEntity<com.rentify.rentify_api.common.response.ApiResponse<Page<PostDeta
363363
schema = @Schema(implementation = Page.class),
364364
examples = @ExampleObject(
365365
value = """
366-
{
366+
367367
"success": true,
368368
"code": "200",
369-
"message": "OK",
369+
"message": "요청이 성공적으로 처리되었습니다.",
370370
"data": {
371371
"content": [
372372
{
373-
"rentalId": 15,
374-
"userId": 2,
375-
"borrowerName": "김빌림",
376-
"postId": 1,
377-
"title": "갤럭시 S25엣지 대여",
378-
"lenderName": "이대여",
379-
"startDate": "2026-02-25",
380-
"endDate": "2026-02-28",
381-
"receiveMethod": "PARCEL",
382-
"status": "IN_PROGRESS",
383-
"thumbnailUrl": "http://unirental.duckdns.org/images/b4485ceb-3e18-4883-bb67-7f29d5f1b805.jpg",
384-
"totalPrice": 156000,
385-
"createdAt": "2026-02-20T14:30:00.123456",
386-
"updatedAt": "2026-02-21T09:15:00.654321"
373+
"canCancel": false,
374+
"canPay": true,
375+
"createdAt": "2026-03-26T10:07:22.185514",
376+
"endDate": "2026-04-01",
377+
"lenderName": "서성민굴",
378+
"paymentId": 22,
379+
"postId": 11,
380+
"postStatus": "AVAILABLE",
381+
"receiveMethod": "MEETUP",
382+
"rentalId": 58,
383+
"rentalStatus": "REQUESTED",
384+
"startDate": "2026-03-31",
385+
"thumbnailUrl": "http://unirental.duckdns.org/images/8b8c4085-dbbf-49a4-9f40-2d89127cd237.jpg",
386+
"title": "갤럭시 울트라 s25 테스트2",
387+
"totalPrice": 60000,
388+
"updatedAt": "2026-03-26T10:07:22.185543",
389+
"userId": 13
390+
},
391+
{
392+
"canCancel": false,
393+
"canPay": false,
394+
"createdAt": "2026-03-26T10:06:29.137002",
395+
"endDate": "2026-03-31",
396+
"lenderName": "서성민굴",
397+
"paymentId": 21,
398+
"postId": 11,
399+
"postStatus": "AVAILABLE",
400+
"receiveMethod": "MEETUP",
401+
"rentalId": 57,
402+
"rentalStatus": "CANCELED",
403+
"startDate": "2026-03-31",
404+
"thumbnailUrl": "http://unirental.duckdns.org/images/8b8c4085-dbbf-49a4-9f40-2d89127cd237.jpg",
405+
"title": "갤럭시 울트라 s25 테스트2",
406+
"totalPrice": 30000,
407+
"updatedAt": "2026-03-26T10:06:44.959271",
408+
"userId": 13
387409
}
388410
],
389411
"page": {
390412
"size": 20,
391413
"number": 0,
392-
"totalElements": 10,
414+
"totalElements": 2,
393415
"totalPages": 1
394416
}
395417
}

0 commit comments

Comments
 (0)