Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,29 @@ public interface RentalApiDocs {
examples = @ExampleObject(
value = """
{
"success": true,
"code": "SUCCESS",
"message": "요청이 성공적으로 처리되었습니다.",
"data": {
"rentalId": 1,
"userId": 1,
"postId": 5,
"startDate": "2026-02-10",
"endDate": "2026-02-15",
"receiveMethod": "PARCEL",
"status": "REQUESTED",
"totalPrice": 250000,
"createdAt": "2026-02-08T10:30:00",
"updatedAt": "2026-02-08T10:30:00"
}
}
"success": true,
"code": "201",
"message": "요청이 성공적으로 처리되었습니다.",
"data": {
"canCancel": false,
"canPay": true,
"createdAt": "2026-03-26T09:38:43.976371",
"endDate": "2026-05-15",
"lenderName": "서성민굴",
"paymentId": null,
"postId": 13,
"postStatus": "AVAILABLE",
"receiveMethod": "PARCEL",
"rentalId": 48,
"rentalStatus": "REQUESTED",
"startDate": "2026-05-10",
"thumbnailUrl": "http://unirental.duckdns.org/images/885bf9e2-3440-4c22-a6b7-138bd24bb27c.jpg",
"title": "갤럭시 s25 울트라 테스트121",
"totalPrice": 210000,
"updatedAt": "2026-03-26T09:38:43.976371",
"userId": 13
}
}
"""
)
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,53 +1,67 @@
package com.rentify.rentify_api.rental.dto;

import com.rentify.rentify_api.payment.entity.Payment;
import com.rentify.rentify_api.payment.entity.PaymentStatus;
import com.rentify.rentify_api.post.entity.PostStatus;
import com.rentify.rentify_api.rental.entity.ReceiveMethod;
import com.rentify.rentify_api.rental.entity.Rental;
import com.rentify.rentify_api.rental.entity.RentalStatus;
import java.time.LocalDate;
import java.time.LocalDateTime;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDate;
import java.time.LocalDateTime;

@Getter
@NoArgsConstructor
@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor(access = AccessLevel.PRIVATE)
@Builder
public class RentalResponse {

private Long rentalId;
private Long userId;
private Long postId;
private String lenderName; // 게시글작성자
// private String borrowerName; // 대여자
private Long paymentId;
private String lenderName;
private String title;
private LocalDate startDate;
private LocalDate endDate;
private ReceiveMethod receiveMethod;
private RentalStatus status;
private PostStatus postStatus;
private RentalStatus rentalStatus;
private String thumbnailUrl;
private Integer totalPrice;
private boolean canPay;
private boolean canCancel;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;

public static RentalResponse from(Rental rental) {
public static RentalResponse of(Rental rental, Payment payment) {
boolean canPay = (payment == null || payment.getStatus() == PaymentStatus.FAILED)
&& (rental.getStatus() == RentalStatus.REQUESTED);
boolean canCancel = (payment != null && payment.getStatus() == PaymentStatus.PAID)
&& (rental.getStatus() == RentalStatus.REQUESTED || rental.getStatus() == RentalStatus.CONFIRMED);

return RentalResponse.builder()
.rentalId(rental.getId())
.userId(rental.getUser().getId())
//.borrowerName(rental.getUser().getName())
.lenderName(rental.getPost().getUser().getName())
.postId(rental.getPost().getId())
.title(rental.getPost().getTitle()) // Post 제목
.startDate(rental.getStartDate())
.endDate(rental.getEndDate())
.receiveMethod(rental.getReceiveMethod())
.status(rental.getStatus())
.thumbnailUrl(rental.getPost().getThumbnailUrl())
.totalPrice(rental.getTotalPrice())
.createdAt(rental.getCreatedAt())
.updatedAt(rental.getUpdatedAt())
.build();
.rentalId(rental.getId())
.userId(rental.getUser().getId())
.paymentId(payment != null ? payment.getId() : null)
.lenderName(rental.getPost().getUser().getName())
.postId(rental.getPost().getId())
.title(rental.getPost().getTitle())
.startDate(rental.getStartDate())
.endDate(rental.getEndDate())
.receiveMethod(rental.getReceiveMethod())
.postStatus(rental.getPost().getStatus())
.rentalStatus(rental.getStatus())
.thumbnailUrl(rental.getPost().getThumbnailUrl())
.totalPrice(rental.getTotalPrice())
.canPay(canPay)
.canCancel(canCancel)
.createdAt(rental.getCreatedAt())
.updatedAt(rental.getUpdatedAt())
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.rentify.rentify_api.rental.repository;

import com.rentify.rentify_api.rental.dto.RentalResponse;
import com.rentify.rentify_api.rental.entity.Rental;
import com.rentify.rentify_api.rental.entity.RentalStatus;
import jakarta.persistence.LockModeType;
Expand Down Expand Up @@ -32,31 +31,40 @@ List<Rental> findOverlappingRentals(

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

// 내가 빌려준 대여 목록
@Query(
value = "SELECT r FROM Rental r " +
"JOIN FETCH r.post p " +
"JOIN FETCH p.user u " +
"WHERE p.user.id = :userId " +
"ORDER BY r.createdAt DESC ",
countQuery = "SELECT count(r) FROM Rental r JOIN r.post p WHERE p.user.id = :userId"
) Page<RentalResponse> findByPostOwnerId(@Param("userId") Long userId, Pageable pageable);
value = "SELECT r, p FROM Rental r " +
"JOIN FETCH r.post po " +
"JOIN FETCH po.user u " +
"LEFT JOIN Payment p ON p.rental = r " +
"AND p.id = (SELECT MAX(p2.id) FROM Payment p2 WHERE p2.rental = r) " +
"WHERE po.user.id = :userId " +
"ORDER BY r.createdAt DESC ",
countQuery = "SELECT count(r) FROM Rental r JOIN r.post po WHERE po.user.id = :userId"
)
Page<Object[]> findByPostOwnerId(@Param("userId") Long userId, Pageable pageable);

// 나의 모든 대여 목록
@Query(
value = "SELECT r FROM Rental r " +
"JOIN FETCH r.post p " +
"JOIN FETCH p.user u " +
"WHERE r.user.id = :userId OR p.user.id = :userId " +
"ORDER BY r.createdAt DESC ",
countQuery = "SELECT count(r) FROM Rental r JOIN r.post p WHERE r.user.id = :userId OR p.user.id = :userId"
) Page<RentalResponse> findByUserIdOrPostOwnerId(@Param("userId") Long userId, Pageable pageable);
value = "SELECT r, p FROM Rental r " +
"JOIN FETCH r.post po " +
"JOIN FETCH po.user u " +
"LEFT JOIN Payment p ON p.rental = r " +
"AND p.id = (SELECT MAX(p2.id) FROM Payment p2 WHERE p2.rental = r) " +
"WHERE r.user.id = :userId OR po.user.id = :userId " +
"ORDER BY r.createdAt DESC ",
countQuery = "SELECT count(r) FROM Rental r JOIN r.post po WHERE r.user.id = :userId OR po.user.id = :userId"
)
Page<Object[]> findByUserIdOrPostOwnerId(@Param("userId") Long userId, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.rentify.rentify_api.rental.service;

import com.rentify.rentify_api.common.exception.NotFoundException;
import com.rentify.rentify_api.payment.entity.Payment;
import com.rentify.rentify_api.post.entity.Post;
import com.rentify.rentify_api.post.entity.PostStatus;
import com.rentify.rentify_api.post.repository.PostRepository;
Expand Down Expand Up @@ -134,11 +135,16 @@ private static RentalResponse convertToResponse(Rental rental) {
.rentalId(rental.getId())
.userId(rental.getUser().getId())
.postId(rental.getPost().getId())
.postStatus(rental.getPost().getStatus())
.lenderName(rental.getPost().getUser().getName())
.thumbnailUrl(rental.getPost().getThumbnailUrl())
.title(rental.getPost().getTitle())
.startDate(rental.getStartDate())
.endDate(rental.getEndDate())
.receiveMethod(rental.getReceiveMethod())
.status(rental.getStatus())
.rentalStatus(rental.getStatus())
.totalPrice(rental.getTotalPrice())
.canPay(true)
.createdAt(rental.getCreatedAt())
.updatedAt(rental.getUpdatedAt())
.build();
Expand Down Expand Up @@ -169,18 +175,30 @@ public RentalResponse cancelRental(Long userId, Long rentalId) {
// 내가 빌리는 대여 목록
@Transactional(readOnly = true)
public Page<RentalResponse> getMyBorrowedRentals(Long userId, Pageable pageable) {
return rentalRepository.findByUserId(userId, pageable);
Page<Object[]> page = rentalRepository.findByUserId(userId, pageable);
return mapToRentalResponsePage(page);
}

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

// 나의 모든 대여 목록
@Transactional(readOnly = true)
public Page<RentalResponse> getMyAllRentals(Long userId, Pageable pageable) {
return rentalRepository.findByUserIdOrPostOwnerId(userId, pageable);
Page<Object[]> page = rentalRepository.findByUserIdOrPostOwnerId(userId, pageable);
return mapToRentalResponsePage(page);
}

private Page<RentalResponse> mapToRentalResponsePage(Page<Object[]> results) {
return results.map(row -> {
Rental rental = (Rental) row[0];
Payment payment = (Payment) row[1];

return RentalResponse.of(rental, payment);
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -363,33 +363,55 @@ ResponseEntity<com.rentify.rentify_api.common.response.ApiResponse<Page<PostDeta
schema = @Schema(implementation = Page.class),
examples = @ExampleObject(
value = """
{

"success": true,
"code": "200",
"message": "OK",
"message": "요청이 성공적으로 처리되었습니다.",
"data": {
"content": [
{
"rentalId": 15,
"userId": 2,
"borrowerName": "김빌림",
"postId": 1,
"title": "갤럭시 S25엣지 대여",
"lenderName": "이대여",
"startDate": "2026-02-25",
"endDate": "2026-02-28",
"receiveMethod": "PARCEL",
"status": "IN_PROGRESS",
"thumbnailUrl": "http://unirental.duckdns.org/images/b4485ceb-3e18-4883-bb67-7f29d5f1b805.jpg",
"totalPrice": 156000,
"createdAt": "2026-02-20T14:30:00.123456",
"updatedAt": "2026-02-21T09:15:00.654321"
"canCancel": false,
"canPay": true,
"createdAt": "2026-03-26T10:07:22.185514",
"endDate": "2026-04-01",
"lenderName": "서성민굴",
"paymentId": 22,
"postId": 11,
"postStatus": "AVAILABLE",
"receiveMethod": "MEETUP",
"rentalId": 58,
"rentalStatus": "REQUESTED",
"startDate": "2026-03-31",
"thumbnailUrl": "http://unirental.duckdns.org/images/8b8c4085-dbbf-49a4-9f40-2d89127cd237.jpg",
"title": "갤럭시 울트라 s25 테스트2",
"totalPrice": 60000,
"updatedAt": "2026-03-26T10:07:22.185543",
"userId": 13
},
{
"canCancel": false,
"canPay": false,
"createdAt": "2026-03-26T10:06:29.137002",
"endDate": "2026-03-31",
"lenderName": "서성민굴",
"paymentId": 21,
"postId": 11,
"postStatus": "AVAILABLE",
"receiveMethod": "MEETUP",
"rentalId": 57,
"rentalStatus": "CANCELED",
"startDate": "2026-03-31",
"thumbnailUrl": "http://unirental.duckdns.org/images/8b8c4085-dbbf-49a4-9f40-2d89127cd237.jpg",
"title": "갤럭시 울트라 s25 테스트2",
"totalPrice": 30000,
"updatedAt": "2026-03-26T10:06:44.959271",
"userId": 13
}
],
"page": {
"size": 20,
"number": 0,
"totalElements": 10,
"totalElements": 2,
"totalPages": 1
}
}
Expand Down