[ 작업한 내용 ]
< 관리자: 도서 대출 반납 처리 >
# AdminLoanReturnResDTO
- 도서 대출 반납 처리 응답 DTO
- 도서 대출 고유번호, 사용자 아이디, 책 제목, 반납일, 상태(id, username, bookTitle, returnDate, status) 으로 엔티티별로 묶어서 응답
- Loan 엔티티를 파라미터로 받는 생성자 함수 정의
** 변경사항 없음
@Getter
public class AdminLoanReturnResDTO {
private Long id;
private String username;
private String bookTitle;
private LocalDateTime returnDate;
private LoanStatus status;
public AdminLoanReturnResDTO(Loan loan) {
this.id = loan.getId();
this.username = loan.getUser().getUsername();
this.bookTitle = loan.getBook().getTitle();
this.returnDate = loan.getReturnDate();
this.status = loan.getStatus();
}
}
# AdminBookController
- PATCH /api/v1/admin/loans/{loanId}/return 로 요청.
- 파라미터로 loanId, @AuthenticationPrincipal User user 전달받음.
- Service 계층으로 loanId, user.getId()를 전달함.
- 결과는 AdminLoanReturnResDTO 형태로 저장.
- 클라이언트 측으로 성공메시지와 결과를 ApiResponse.success()로 감싸서 응답.
** 사용자 인증 객체 코드 추가
@PatchMapping("/{loanId}/return")
public ResponseEntity<?> returnLoan(
@PathVariable("loanId") Long loanId,
@AuthenticationPrincipal User user) {
// 서비스로직
AdminLoanReturnResDTO responseDTO = adminLoanService.returnLoan(loanId, user.getId());
// 성공메시지
String message = messageProvider.getMessage(LoanSuccessCode.LOAN_RETURNED.getMessage());
return ResponseEntity
.status(LoanSuccessCode.LOAN_RETURNED.getHttpStatus())
.body(ApiResponse.success(
LoanSuccessCode.LOAN_RETURNED,
message,
responseDTO));
}
# AdminBookService
- userRepository.findById(userId) 사용하여 사용자 조회 후 User로 저장. 만약에 조회가 안된다면 UserErrorCode.USER_NOT_FOUND 예외를 발생 시킴.
- user.getRole()으로 권한이 관리자인지 체크하고 관리자가 아니라면 AuthErrorCode.AUTH_FORBIDDEN 예외를 발생 시킴.
- loanRepository.findById(loanId)를 사용하여 도서 대출 내역을 조회하여 Loan loan으로 저장. 만약에 조회가 안된다면 LoanErrorCode.LOAN_NOT_FOUND 예외를 발생 시킴.
- bookRepository.findById(loan.getBook().getId())를 사용하여 도서 내역을 조회하여 Book book으로 저장. 만약에 조회가 안된다면 BookErrorCode.BOOK_NOT_FOUND 예외를 발생시킴.
- loan의 상태가 반납된 상태인지 체크하고 반납이 이미 되었다면 LoanErrorCode.LOAN_ALREADY_RETURNED 예외를 발생 시킴.
- 대출 내역 반납 날짜와 상태를 변경.
- 도서 상태와 수정날짜를 변경.
- Controller로 loan을 기반으로 AdminLoanReturnResDTO 객체를 생성하여 반환.
** 관리자 권한 체크 코드 추가
@Transactional
public AdminLoanReturnResDTO returnLoan(Long loanId, Long userId) {
// 관리자 권환 조회 및 예외 처리
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
if (user.getRole() != Role.ROLE_ADMIN) {
throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
}
// Loan 엔티티 조회 + 예외 처리
Loan loan = loanRepository.findById(loanId)
.orElseThrow(() -> new BaseException(LoanErrorCode.LOAN_NOT_FOUND));
// Book 엔티티 조회
Book book = bookRepository.findById(loan.getBook().getId())
.orElseThrow(() -> new BaseException(BookErrorCode.BOOK_NOT_FOUND));
// loan 상태 체크 (반납이 된 상태인지)
if (loan.getStatus() == LoanStatus.RETURNED) {
throw new BaseException(LoanErrorCode.LOAN_ALREADY_RETURNED);
}
// 대출 내역 반납 시간과 상태 변경
loan.setReturnDate(LocalDateTime.now());
loan.setStatus(LoanStatus.RETURNED);
// 도서 상태와 수정 시간 변경
book.setStatus(BookStatus.AVAILABLE);
book.setUpdatedAt(LocalDateTime.now());
// 변경된 loan 반환
return new AdminLoanReturnResDTO(loan);
}
< 관리자: 도서 대출 연장 처리 >
# AdminLoanExtendedResDTO
- 도서 대출 연장 처리 응답 DTO
- 도서 대출 고유번호, 사용자 아이디, 책 제목, 대출일, 연장일, 연장 여부, 상태 (id, username, bookTitle, loanDate, dueDate, extended status) 으로 엔티티별로 묶어서 응답
- Loan 엔티티를 파라미터로 받는 생성자 함수 정의
** 변경사항 없음
@Getter
public class AdminLoanExtendedResDTO {
private Long id;
private String username;
private String bookTitle;
private LocalDateTime loanDate;
private LocalDateTime dueDate;
private boolean extended;
private LoanStatus status;
public AdminLoanExtendedResDTO(Loan loan) {
this.id = loan.getId();
this.username = loan.getUser().getUsername();
this.bookTitle = loan.getBook().getTitle();
this.loanDate = loan.getLoanDate();
this.dueDate = loan.getDueDate();
this.extended = loan.isExtended();
this.status = loan.getStatus();
}
}
# AdminBookController
- PATCH /api/v1/admin/loans/{loanId}/extend 로 요청.
- 파라미터로 loanId, @AuthenticationPrincipal User user 전달받음.
- Service 계층으로 loanId, user.getId()를 전달함.
- 결과는 AdminLoanExtendedResDTO 형태로 저장.
- 클라이언트 측으로 성공메시지와 결과를 ApiResponse.success()로 감싸서 응답.
** 사용자 인증 객체 코드 추가
@PatchMapping("/{loanId}/extend")
public ResponseEntity<?> extendLoan(
@PathVariable("loanId") Long loanId,
@AuthenticationPrincipal User user) {
// 서비스로직
AdminLoanExtendedResDTO responseDTO = adminLoanService.extendLoan(loanId, user.getId());
// 성공메시지
String message = messageProvider.getMessage(LoanSuccessCode.LOAN_EXTENDED.getMessage());
// 응답
return ResponseEntity
.status(LoanSuccessCode.LOAN_EXTENDED.getHttpStatus())
.body(ApiResponse.success(
LoanSuccessCode.LOAN_EXTENDED,
message,
responseDTO));
}
# AdminBookService
- userRepository.findById(userId) 사용하여 사용자 조회 후 User로 저장. 만약에 조회가 안된다면 UserErrorCode.USER_NOT_FOUND 예외를 발생 시킴.
- user.getRole()으로 권한이 관리자인지 체크하고 관리자가 아니라면 AuthErrorCode.AUTH_FORBIDDEN 예외를 발생 시킴.
- loanRepository.findById(loanId)를 사용하여 도서 대출 내역을 조회하여 Loan loan으로 저장. 만약에 조회가 안된다면 LoanErrorCode.LOAN_NOT_FOUND 예외를 발생 시킴.
- loan의 상태가 LOANED(대출중)인 상태인지 체크. 만약에 아니라면 LoanErrorCode.LOAN_CANNOT_EXTEND 예외를 발생 시킴.
- loan의 대출 연장 여부 체크. 만약에 한 번이라도 연장이 되었다면 연장 불가. 그래서 LoanErrorCode.LOAN_ALREADY_EXTENDED 예외를 발생 시킴.
- 대출 연장 여부를 true로, 반납일을 기존 일에서 7일 추가하여 수정.
- Controller로 loan을 기반으로 AdminLoanExtendedResDTO 객체를 생성하여 반환.
** 관리자 권한 체크 코드 추가, 주석 수정
@Transactional
public AdminLoanExtendedResDTO extendLoan(Long loanId, Long userId) {
// 관리자 권환 조회 및 예외 처리
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
if (user.getRole() != Role.ROLE_ADMIN) {
throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
}
// loanId로 조회 및 예외처리
Loan loan = loanRepository.findById(loanId)
.orElseThrow(() -> new BaseException(LoanErrorCode.LOAN_NOT_FOUND));
// loan 상태가 대출중인 것만 가능
// 연체, 반납, 분실 상태는 불가
if (loan.getStatus() != LoanStatus.LOANED) {
throw new BaseException(LoanErrorCode.LOAN_CANNOT_EXTEND);
}
// loan 대출 연장 여부 체크 및 예외처리
if (loan.isExtended() != false) {
throw new BaseException(LoanErrorCode.LOAN_ALREADY_EXTENDED);
}
// 대출 연장 및 반납 기간 업데이트
// 대출 연장은 1회 가능, 7일 추가
loan.setExtended(true);
loan.setDueDate(loan.getDueDate().plusDays(7));
// 반환
return new AdminLoanExtendedResDTO(loan);
}
< 관리자: 도서 분실 처리 >
# BookLostDTO
- 도서 분실 처리 응답 DTO 중 Book 엔티티 DTO
- 도서 고유번호, 도서 제목, 도서 상태, 도서 분실일 (id, title, status, lostedAt)
- Book 엔티티를 파라미터로 받는 생서자 함수 정의
@Getter
public class BookLostDTO {
private Long id;
private String title;
private BookStatus status;
private LocalDateTime lostedAt;
public BookLostDTO(Book book) {
this.id = book.getId();
this.title = book.getTitle();
this.status = book.getStatus();
this.lostedAt = book.getLostedAt();
}
}
# LoanLostDTO
- 도서 분실 처리 응답 DTO 중 Loan 엔티티 DTO
- 도서 대출 고유번호, 대출 상태, 분실 날짜 (id, loanStatus, lostDate)
- Loan 엔티티를 파라미터로 받는 생성자 함수 정의
@Getter
public class LoanLostDTO {
private Long id;
private LoanStatus loanStatus;
private LocalDateTime lostDate;
public LoanLostDTO(Loan loan) {
this.id = loan.getId();
this.loanStatus = loan.getStatus();
this.lostDate = loan.getLostDate();
}
}
# AdminLoanLostResDTO
- 도서 분실 처리 응답 DTO
- loan, book, user 엔티티로 구분
- Loan 엔티티를 파라미터로 받는 생성자 함수 정의
** 도서 대출, 도서, 사용자 구분을 위해서 그룹으로 묶어서 구분
@Getter
public class AdminLoanLostResDTO {
private LoanLostDTO loan;
private BookLostDTO book;
private BorrowerDTO user;
public AdminLoanLostResDTO(Loan loan) {
this.loan = new LoanLostDTO(loan);
this.book = new BookLostDTO(loan.getBook());
this.user = new BorrowerDTO(loan.getUser());
}
}
# AdminBookController
- PATCH /api/v1/admin/loans/{loanId}/lost 로 요청.
- 파라미터로 loanId, @AuthenticationPrincipal User user 전달받음.
- Service 계층으로 loanId, user.getId()를 전달함.
- 결과는 AdminLoanLostResDTO 형태로 저장.
- 클라이언트 측으로 성공메시지와 결과를 ApiResponse.success()로 감싸서 응답.
** 사용자 인증 객체 코드 추가
@PatchMapping("/{loanId}/lost")
public ResponseEntity<?> loanLostBook(
@PathVariable("loanId") Long loanId,
@AuthenticationPrincipal User user) {
// 서비스로직
AdminLoanLostResDTO responseDTO = adminLoanService.loanLostBook(loanId, user.getId());
// 성공메시지
String message = messageProvider.getMessage(LoanSuccessCode.LOAN_MARKED_AS_LOST.getMessage());
// 응답
return ResponseEntity
.status(LoanSuccessCode.LOAN_MARKED_AS_LOST.getHttpStatus())
.body(ApiResponse.success(
LoanSuccessCode.LOAN_MARKED_AS_LOST,
message,
responseDTO));
}
# AdminBookService
- userRepository.findById(userId) 사용하여 사용자 조회 후 User로 저장. 만약에 조회가 안된다면 UserErrorCode.USER_NOT_FOUND 예외를 발생 시킴.
- user.getRole()으로 권한이 관리자인지 체크하고 관리자가 아니라면 AuthErrorCode.AUTH_FORBIDDEN 예외를 발생 시킴.
- loanRepository.findById(loanId)를 사용하여 도서 대출 내역을 조회하여 Loan loan으로 저장. 만약에 조회가 안된다면 LoanErrorCode.LOAN_NOT_FOUND 예외를 발생 시킴.
- bookRepository.findById(loan.getBook().getId())를 사용하여 도서를 조회하여 Book book으로 저장. 만약에 조회가 안된다면 BookErrorCode.BOOK_NOT_FOUND 예외를 발생 시킴.
- loan의 상태가 LOST인지 체크. LOST가 아니라면 LoanErrorCode.LOAN_ALREADY_LOST 예외를 발생 시킴.
- loan의 상태가 LOANED, OVERDUE만 LOST 처리 가능. 아니라면 LOAN_STATUS_INVALID_FOR_LOST 예외를 발생 시킴.
- book의 상태가 LOST인지 체크 후 이미 LOST면 BookErrorCode.BOOK_ALREADY_LOST 예외를 발생 시킴.
- 도서 대출 내역과 도서 상태 분실 처리.
- Controller로 loan을 기반으로 AdminLoanLostResDTO 생성하여 반환.
** 사용자 인증 객체 코드 추가, 관리자 권한 체크 코드 추가
@Transactional
public AdminLoanLostResDTO loanLostBook(Long loanId, Long userId) {
// 관리자 권환 조회 및 예외 처리
User user = userRepository.findById(userId)
.orElseThrow(() -> new BaseException(UserErrorCode.USER_NOT_FOUND));
if (user.getRole() != Role.ROLE_ADMIN) {
throw new BaseException(AuthErrorCode.AUTH_FORBIDDEN);
}
// loanId 조회 + 예외 처리
Loan loan = loanRepository.findById(loanId)
.orElseThrow(() -> new BaseException(LoanErrorCode.LOAN_NOT_FOUND));
// bookId 조회 + 예외 처리
Book book = bookRepository.findById(loan.getBook().getId())
.orElseThrow(() -> new BaseException(BookErrorCode.BOOK_NOT_FOUND));
// Loan 엔티티 LOST 상태 여부 체크 + 예외 처리
if (loan.getStatus() == LoanStatus.LOST) {
throw new BaseException(LoanErrorCode.LOAN_ALREADY_LOST);
}
// Loan 상태가 LOANED, OVERDUE만 LOST 처리 가능
LoanStatus current = loan.getStatus();
if (current != LoanStatus.LOANED && current != LoanStatus.OVERDUE) {
throw new BaseException(LoanErrorCode.LOAN_STATUS_INVALID_FOR_LOST);
}
// Book 엔티티 상태 체크 후 분실 처리
if (book.getStatus() == BookStatus.LOST) {
throw new BaseException(BookErrorCode.BOOK_ALREADY_LOST);
}
// 도서 대출 내역과 도서 상태 분실 처리
loan.setStatus(LoanStatus.LOST);
loan.setLostDate(LocalDateTime.now());
book.setStatus(BookStatus.LOST);
book.setLostedAt(LocalDateTime.now());
// 응답
return new AdminLoanLostResDTO(loan);
}