From 09a6a2176b28957fa06ecc48e425e64ab107f3dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=85=B8=EA=B2=BD=EB=AF=BC?= Date: Wed, 6 Dec 2023 17:10:50 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EC=8B=9C=ED=97=98=20=EC=B0=A8=EB=9F=89?= =?UTF-8?q?=20=EC=98=88=EC=95=BD=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=20(#21)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 디렉토리 구조 변경 #8 * feat: 차량 예약 조회 및 예약 기능 구현 #8 --- .../car/domains/car/CarController.java | 1 + .../testcar/car/domains/car/CarService.java | 1 + .../car/domains/car/{ => entity}/Car.java | 2 +- .../car/domains/car/{ => entity}/Type.java | 2 +- .../car/domains/car/model/CarResponse.java | 4 +- .../domains/car/model/RegisterCarRequest.java | 2 +- .../car/model/vo/CarFilterCondition.java | 2 +- .../car/repository/CarCustomRepository.java | 2 +- .../repository/CarCustomRepositoryImpl.java | 6 +- .../domains/car/repository/CarRepository.java | 2 +- .../CarReservationController.java | 52 +++++++++++++ .../carReservation/CarReservationService.java | 57 ++++++++++++++ .../{ => entity}/CarReservation.java | 21 +++-- .../{ => entity}/ReservationStatus.java | 6 +- .../carReservation/exception/ErrorCode.java | 15 ++++ .../model/CarReservationResponse.java | 60 +++++++++++++++ .../model/dto/CarReservationDto.java | 28 +++++++ .../vo/CarReservationFilterCondition.java | 27 +++++++ .../CarReservationCustomRepository.java | 12 +++ .../CarReservationCustomRepositoryImpl.java | 77 +++++++++++++++++++ .../repository/CarReservationRepository.java | 8 ++ .../domains/carStock/CarStockController.java | 1 + .../car/domains/carStock/CarStockService.java | 3 +- .../carStock/{ => entity}/CarStock.java | 4 +- .../carStock/{ => entity}/StockStatus.java | 2 +- .../carStock/model/CarStockResponse.java | 4 +- .../model/RegisterCarStockRequest.java | 2 +- .../carStock/model/UpdateCarStockRequest.java | 2 +- .../model/vo/CarStockFilterCondition.java | 2 +- .../repository/CarStockCustomRepository.java | 2 +- .../CarStockCustomRepositoryImpl.java | 8 +- .../repository/CarStockRepository.java | 2 +- .../testcar/car/domains/carTest/CarTest.java | 2 +- .../GasStationHistoryService.java | 2 +- .../entity/GasStationHistory.java | 2 +- .../db/migration/V6__UpdateCarReservation.sql | 10 +++ 36 files changed, 396 insertions(+), 39 deletions(-) rename src/main/java/com/testcar/car/domains/car/{ => entity}/Car.java (96%) rename src/main/java/com/testcar/car/domains/car/{ => entity}/Type.java (84%) create mode 100644 src/main/java/com/testcar/car/domains/carReservation/CarReservationController.java create mode 100644 src/main/java/com/testcar/car/domains/carReservation/CarReservationService.java rename src/main/java/com/testcar/car/domains/carReservation/{ => entity}/CarReservation.java (74%) rename src/main/java/com/testcar/car/domains/carReservation/{ => entity}/ReservationStatus.java (59%) create mode 100644 src/main/java/com/testcar/car/domains/carReservation/exception/ErrorCode.java create mode 100644 src/main/java/com/testcar/car/domains/carReservation/model/CarReservationResponse.java create mode 100644 src/main/java/com/testcar/car/domains/carReservation/model/dto/CarReservationDto.java create mode 100644 src/main/java/com/testcar/car/domains/carReservation/model/vo/CarReservationFilterCondition.java create mode 100644 src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationCustomRepository.java create mode 100644 src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationCustomRepositoryImpl.java create mode 100644 src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationRepository.java rename src/main/java/com/testcar/car/domains/carStock/{ => entity}/CarStock.java (94%) rename src/main/java/com/testcar/car/domains/carStock/{ => entity}/StockStatus.java (85%) create mode 100644 src/main/resources/db/migration/V6__UpdateCarReservation.sql diff --git a/src/main/java/com/testcar/car/domains/car/CarController.java b/src/main/java/com/testcar/car/domains/car/CarController.java index 2176afc..ac5b024 100644 --- a/src/main/java/com/testcar/car/domains/car/CarController.java +++ b/src/main/java/com/testcar/car/domains/car/CarController.java @@ -3,6 +3,7 @@ import com.testcar.car.common.annotation.RoleAllowed; import com.testcar.car.common.response.PageResponse; +import com.testcar.car.domains.car.entity.Car; import com.testcar.car.domains.car.model.CarResponse; import com.testcar.car.domains.car.model.RegisterCarRequest; import com.testcar.car.domains.car.model.vo.CarFilterCondition; diff --git a/src/main/java/com/testcar/car/domains/car/CarService.java b/src/main/java/com/testcar/car/domains/car/CarService.java index 7ba5a45..b227da1 100644 --- a/src/main/java/com/testcar/car/domains/car/CarService.java +++ b/src/main/java/com/testcar/car/domains/car/CarService.java @@ -3,6 +3,7 @@ import com.testcar.car.common.exception.BadRequestException; import com.testcar.car.common.exception.NotFoundException; +import com.testcar.car.domains.car.entity.Car; import com.testcar.car.domains.car.exception.ErrorCode; import com.testcar.car.domains.car.model.RegisterCarRequest; import com.testcar.car.domains.car.model.vo.CarFilterCondition; diff --git a/src/main/java/com/testcar/car/domains/car/Car.java b/src/main/java/com/testcar/car/domains/car/entity/Car.java similarity index 96% rename from src/main/java/com/testcar/car/domains/car/Car.java rename to src/main/java/com/testcar/car/domains/car/entity/Car.java index bec9396..ac26d8a 100644 --- a/src/main/java/com/testcar/car/domains/car/Car.java +++ b/src/main/java/com/testcar/car/domains/car/entity/Car.java @@ -1,4 +1,4 @@ -package com.testcar.car.domains.car; +package com.testcar.car.domains.car.entity; import com.testcar.car.common.entity.BaseEntity; diff --git a/src/main/java/com/testcar/car/domains/car/Type.java b/src/main/java/com/testcar/car/domains/car/entity/Type.java similarity index 84% rename from src/main/java/com/testcar/car/domains/car/Type.java rename to src/main/java/com/testcar/car/domains/car/entity/Type.java index 8708c67..deda305 100644 --- a/src/main/java/com/testcar/car/domains/car/Type.java +++ b/src/main/java/com/testcar/car/domains/car/entity/Type.java @@ -1,4 +1,4 @@ -package com.testcar.car.domains.car; +package com.testcar.car.domains.car.entity; import lombok.Getter; diff --git a/src/main/java/com/testcar/car/domains/car/model/CarResponse.java b/src/main/java/com/testcar/car/domains/car/model/CarResponse.java index ac9357d..2baf59b 100644 --- a/src/main/java/com/testcar/car/domains/car/model/CarResponse.java +++ b/src/main/java/com/testcar/car/domains/car/model/CarResponse.java @@ -2,8 +2,8 @@ import com.testcar.car.common.annotation.DateTimeFormat; -import com.testcar.car.domains.car.Car; -import com.testcar.car.domains.car.Type; +import com.testcar.car.domains.car.entity.Car; +import com.testcar.car.domains.car.entity.Type; import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDateTime; import lombok.Builder; diff --git a/src/main/java/com/testcar/car/domains/car/model/RegisterCarRequest.java b/src/main/java/com/testcar/car/domains/car/model/RegisterCarRequest.java index aa447f3..390f521 100644 --- a/src/main/java/com/testcar/car/domains/car/model/RegisterCarRequest.java +++ b/src/main/java/com/testcar/car/domains/car/model/RegisterCarRequest.java @@ -1,7 +1,7 @@ package com.testcar.car.domains.car.model; -import com.testcar.car.domains.car.Type; +import com.testcar.car.domains.car.entity.Type; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/testcar/car/domains/car/model/vo/CarFilterCondition.java b/src/main/java/com/testcar/car/domains/car/model/vo/CarFilterCondition.java index 03471bd..3df5fbf 100644 --- a/src/main/java/com/testcar/car/domains/car/model/vo/CarFilterCondition.java +++ b/src/main/java/com/testcar/car/domains/car/model/vo/CarFilterCondition.java @@ -2,7 +2,7 @@ import com.testcar.car.common.annotation.DateTimeFormat; -import com.testcar.car.domains.car.Type; +import com.testcar.car.domains.car.entity.Type; import io.swagger.v3.oas.annotations.media.Schema; import java.time.LocalDateTime; import lombok.Getter; diff --git a/src/main/java/com/testcar/car/domains/car/repository/CarCustomRepository.java b/src/main/java/com/testcar/car/domains/car/repository/CarCustomRepository.java index 7297e0c..e88504c 100644 --- a/src/main/java/com/testcar/car/domains/car/repository/CarCustomRepository.java +++ b/src/main/java/com/testcar/car/domains/car/repository/CarCustomRepository.java @@ -1,7 +1,7 @@ package com.testcar.car.domains.car.repository; -import com.testcar.car.domains.car.Car; +import com.testcar.car.domains.car.entity.Car; import com.testcar.car.domains.car.model.vo.CarFilterCondition; import java.util.Optional; import org.springframework.data.domain.Page; diff --git a/src/main/java/com/testcar/car/domains/car/repository/CarCustomRepositoryImpl.java b/src/main/java/com/testcar/car/domains/car/repository/CarCustomRepositoryImpl.java index 09ac3fa..be0b47c 100644 --- a/src/main/java/com/testcar/car/domains/car/repository/CarCustomRepositoryImpl.java +++ b/src/main/java/com/testcar/car/domains/car/repository/CarCustomRepositoryImpl.java @@ -1,12 +1,12 @@ package com.testcar.car.domains.car.repository; -import static com.testcar.car.domains.car.QCar.car; +import static com.testcar.car.domains.car.entity.QCar.car; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import com.testcar.car.common.entity.BaseQueryDslRepository; -import com.testcar.car.domains.car.Car; -import com.testcar.car.domains.car.Type; +import com.testcar.car.domains.car.entity.Car; +import com.testcar.car.domains.car.entity.Type; import com.testcar.car.domains.car.model.vo.CarFilterCondition; import java.time.LocalDateTime; import java.util.List; diff --git a/src/main/java/com/testcar/car/domains/car/repository/CarRepository.java b/src/main/java/com/testcar/car/domains/car/repository/CarRepository.java index 7da5f78..953b07a 100644 --- a/src/main/java/com/testcar/car/domains/car/repository/CarRepository.java +++ b/src/main/java/com/testcar/car/domains/car/repository/CarRepository.java @@ -1,7 +1,7 @@ package com.testcar.car.domains.car.repository; -import com.testcar.car.domains.car.Car; +import com.testcar.car.domains.car.entity.Car; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/testcar/car/domains/carReservation/CarReservationController.java b/src/main/java/com/testcar/car/domains/carReservation/CarReservationController.java new file mode 100644 index 0000000..5e7e2b6 --- /dev/null +++ b/src/main/java/com/testcar/car/domains/carReservation/CarReservationController.java @@ -0,0 +1,52 @@ +package com.testcar.car.domains.carReservation; + + +import com.testcar.car.common.annotation.AuthMember; +import com.testcar.car.common.annotation.RoleAllowed; +import com.testcar.car.common.response.PageResponse; +import com.testcar.car.domains.carReservation.entity.CarReservation; +import com.testcar.car.domains.carReservation.model.CarReservationResponse; +import com.testcar.car.domains.carReservation.model.dto.CarReservationDto; +import com.testcar.car.domains.carReservation.model.vo.CarReservationFilterCondition; +import com.testcar.car.domains.member.Member; +import com.testcar.car.domains.member.Role; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.springdoc.core.annotations.ParameterObject; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@Tag(name = "[시험차량 관리] ", description = "시험차량 관리 API") +@RestController +@RequestMapping("/cars") +@RequiredArgsConstructor +public class CarReservationController { + private final CarReservationService carReservationService; + + @GetMapping("/reservations") + @RoleAllowed(role = Role.USER) + @Operation(summary = "[시험차량 관리] 시험차량 대여 이력", description = "조건에 맞는 시험차량 대여 이력을 모두 조회합니다.") + public PageResponse getCarReservationsByCondition( + @ParameterObject @ModelAttribute CarReservationFilterCondition condition, + @ParameterObject Pageable pageable) { + final Page carReservations = + carReservationService.findAllPageByCondition(condition, pageable); + return PageResponse.from(carReservations.map(CarReservationResponse::from)); + } + + @PostMapping("/{carStockId}/reserve") + @RoleAllowed(role = Role.USER) + @Operation(summary = "[시험차량 관리] 시험차량 대여", description = "시험 차량을 예약합니다.") + public CarReservationResponse postCarReservation( + @AuthMember Member member, @PathVariable Long carStockId) { + final CarReservation carReservation = carReservationService.reserve(member, carStockId); + return CarReservationResponse.from(carReservation); + } +} diff --git a/src/main/java/com/testcar/car/domains/carReservation/CarReservationService.java b/src/main/java/com/testcar/car/domains/carReservation/CarReservationService.java new file mode 100644 index 0000000..f06393a --- /dev/null +++ b/src/main/java/com/testcar/car/domains/carReservation/CarReservationService.java @@ -0,0 +1,57 @@ +package com.testcar.car.domains.carReservation; + +import static com.testcar.car.domains.carStock.entity.StockStatus.AVAILABLE; + +import com.testcar.car.common.exception.BadRequestException; +import com.testcar.car.domains.carReservation.entity.CarReservation; +import com.testcar.car.domains.carReservation.exception.ErrorCode; +import com.testcar.car.domains.carReservation.model.dto.CarReservationDto; +import com.testcar.car.domains.carReservation.model.vo.CarReservationFilterCondition; +import com.testcar.car.domains.carReservation.repository.CarReservationRepository; +import com.testcar.car.domains.carStock.CarStockService; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.member.Member; +import java.time.LocalDateTime; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class CarReservationService { + private static final int RESERVATION_DATE = 7; + + private final CarStockService carStockService; + private final CarReservationRepository carReservationRepository; + + /** 조건에 맞는 시험차량 대여 이력을 조회합니다. */ + public Page findAllPageByCondition( + CarReservationFilterCondition condition, Pageable pageable) { + return carReservationRepository.findAllPageByCondition(condition, pageable); + } + + /** 시험차량을 예약합니다. */ + public CarReservation reserve(Member member, Long carStockId) { + final CarStock carStock = carStockService.findById(carStockId); + validateCarStockAvailable(carStock); + final LocalDateTime now = LocalDateTime.now(); + final LocalDateTime expiredAt = now.toLocalDate().plusDays(RESERVATION_DATE).atStartOfDay(); + final CarReservation carReservation = + CarReservation.builder() + .member(member) + .carStock(carStock) + .startedAt(now) + .expiredAt(expiredAt) + .build(); + return carReservationRepository.save(carReservation); + } + + public void validateCarStockAvailable(CarStock carStock) { + if (carStock.getStatus() != AVAILABLE) { + throw new BadRequestException(ErrorCode.CAR_STOCK_NOT_AVAILABLE); + } + } +} diff --git a/src/main/java/com/testcar/car/domains/carReservation/CarReservation.java b/src/main/java/com/testcar/car/domains/carReservation/entity/CarReservation.java similarity index 74% rename from src/main/java/com/testcar/car/domains/carReservation/CarReservation.java rename to src/main/java/com/testcar/car/domains/carReservation/entity/CarReservation.java index 9c420cc..e0a77db 100644 --- a/src/main/java/com/testcar/car/domains/carReservation/CarReservation.java +++ b/src/main/java/com/testcar/car/domains/carReservation/entity/CarReservation.java @@ -1,8 +1,8 @@ -package com.testcar.car.domains.carReservation; +package com.testcar.car.domains.carReservation.entity; import com.testcar.car.common.entity.BaseEntity; -import com.testcar.car.domains.carStock.CarStock; +import com.testcar.car.domains.carStock.entity.CarStock; import com.testcar.car.domains.member.Member; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -41,9 +41,13 @@ public class CarReservation extends BaseEntity { @JoinColumn(name = "carStockId", nullable = false) private CarStock carStock; - // 대여시각 + // 대여 시각 @Column(nullable = false) - private LocalDateTime reservedAt; + private LocalDateTime startedAt; + + // 대여 만료시각 + @Column(nullable = false) + private LocalDateTime expiredAt; // 대여상태 @Column(nullable = false) @@ -52,10 +56,15 @@ public class CarReservation extends BaseEntity { @Builder public CarReservation( - Member member, CarStock carStock, LocalDateTime reservedAt, ReservationStatus status) { + Member member, + CarStock carStock, + LocalDateTime startedAt, + LocalDateTime expiredAt, + ReservationStatus status) { this.member = member; this.carStock = carStock; - this.reservedAt = reservedAt; + this.startedAt = startedAt; + this.expiredAt = expiredAt; this.status = status; } } diff --git a/src/main/java/com/testcar/car/domains/carReservation/ReservationStatus.java b/src/main/java/com/testcar/car/domains/carReservation/entity/ReservationStatus.java similarity index 59% rename from src/main/java/com/testcar/car/domains/carReservation/ReservationStatus.java rename to src/main/java/com/testcar/car/domains/carReservation/entity/ReservationStatus.java index 5012abc..129637b 100644 --- a/src/main/java/com/testcar/car/domains/carReservation/ReservationStatus.java +++ b/src/main/java/com/testcar/car/domains/carReservation/entity/ReservationStatus.java @@ -1,4 +1,4 @@ -package com.testcar.car.domains.carReservation; +package com.testcar.car.domains.carReservation.entity; import lombok.Getter; @@ -7,10 +7,8 @@ @Getter @RequiredArgsConstructor public enum ReservationStatus { - AVAILABLE("대여 가능"), - INSPECTION("검수중"), RESERVED("대여중"), - UNAVAILABLE("폐기"); + RETURNED("반납완료"); private final String description; } diff --git a/src/main/java/com/testcar/car/domains/carReservation/exception/ErrorCode.java b/src/main/java/com/testcar/car/domains/carReservation/exception/ErrorCode.java new file mode 100644 index 0000000..8e02095 --- /dev/null +++ b/src/main/java/com/testcar/car/domains/carReservation/exception/ErrorCode.java @@ -0,0 +1,15 @@ +package com.testcar.car.domains.carReservation.exception; + + +import com.testcar.car.common.exception.BaseErrorCode; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum ErrorCode implements BaseErrorCode { + CAR_STOCK_NOT_AVAILABLE("CRS001", "해당 재고는 대여 불가합니다."); + + private final String code; + private final String message; +} diff --git a/src/main/java/com/testcar/car/domains/carReservation/model/CarReservationResponse.java b/src/main/java/com/testcar/car/domains/carReservation/model/CarReservationResponse.java new file mode 100644 index 0000000..c419016 --- /dev/null +++ b/src/main/java/com/testcar/car/domains/carReservation/model/CarReservationResponse.java @@ -0,0 +1,60 @@ +package com.testcar.car.domains.carReservation.model; + + +import com.testcar.car.common.annotation.DateFormat; +import com.testcar.car.domains.carReservation.entity.CarReservation; +import com.testcar.car.domains.carReservation.entity.ReservationStatus; +import com.testcar.car.domains.carReservation.model.dto.CarReservationDto; +import com.testcar.car.domains.carStock.entity.CarStock; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; +import lombok.Builder; +import lombok.Getter; + +@Getter +@Builder +public class CarReservationResponse { + @Schema(description = "차량 예약 ID", example = "1") + private final Long id; + + @Schema(description = "차량명", example = "아반떼") + private final String name; + + @Schema(description = "차량 재고번호", example = "2023010300001") + private final String stockNumber; + + @DateFormat + @Schema(description = "차량 대여 시작일", example = "2021-01-01") + private final LocalDateTime startedAt; + + @DateFormat + @Schema(description = "차량 대여 만료일", example = "2021-01-08") + private final LocalDateTime expiredAt; + + @Schema(description = "대여 상태", example = "RESERVED", implementation = ReservationStatus.class) + private final ReservationStatus status; + + public static CarReservationResponse from(CarReservationDto carReservationDto) { + return CarReservationResponse.builder() + .id(carReservationDto.getId()) + .name(carReservationDto.getCarName()) + .stockNumber(carReservationDto.getStockNumber()) + .startedAt(carReservationDto.getStartedAt()) + .expiredAt(carReservationDto.getExpiredAt()) + .status(carReservationDto.getStatus()) + .build(); + } + + public static CarReservationResponse from(CarReservation carReservation) { + final CarStock carStock = carReservation.getCarStock(); + + return CarReservationResponse.builder() + .id(carReservation.getId()) + .name(carStock.getCar().getName()) + .stockNumber(carStock.getStockNumber()) + .startedAt(carReservation.getStartedAt()) + .expiredAt(carReservation.getExpiredAt()) + .status(carReservation.getStatus()) + .build(); + } +} diff --git a/src/main/java/com/testcar/car/domains/carReservation/model/dto/CarReservationDto.java b/src/main/java/com/testcar/car/domains/carReservation/model/dto/CarReservationDto.java new file mode 100644 index 0000000..37f92e4 --- /dev/null +++ b/src/main/java/com/testcar/car/domains/carReservation/model/dto/CarReservationDto.java @@ -0,0 +1,28 @@ +package com.testcar.car.domains.carReservation.model.dto; + + +import com.querydsl.core.annotations.QueryProjection; +import com.testcar.car.domains.carReservation.entity.CarReservation; +import com.testcar.car.domains.carReservation.entity.ReservationStatus; +import java.time.LocalDateTime; +import lombok.Getter; + +@Getter +public class CarReservationDto { + private final Long id; + private final String carName; + private final String stockNumber; + private final LocalDateTime startedAt; + private final LocalDateTime expiredAt; + private final ReservationStatus status; + + @QueryProjection + public CarReservationDto(CarReservation carReservation, String carName, String stockNumber) { + this.id = carReservation.getId(); + this.carName = carName; + this.stockNumber = stockNumber; + this.startedAt = carReservation.getStartedAt(); + this.expiredAt = carReservation.getExpiredAt(); + this.status = carReservation.getStatus(); + } +} diff --git a/src/main/java/com/testcar/car/domains/carReservation/model/vo/CarReservationFilterCondition.java b/src/main/java/com/testcar/car/domains/carReservation/model/vo/CarReservationFilterCondition.java new file mode 100644 index 0000000..1b4f634 --- /dev/null +++ b/src/main/java/com/testcar/car/domains/carReservation/model/vo/CarReservationFilterCondition.java @@ -0,0 +1,27 @@ +package com.testcar.car.domains.carReservation.model.vo; + + +import com.testcar.car.common.annotation.DateFormat; +import com.testcar.car.domains.carReservation.entity.ReservationStatus; +import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDate; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class CarReservationFilterCondition { + @Schema(description = "차량명", example = "null") + private String name; + + @Schema(description = "대여 상태", example = "null", implementation = ReservationStatus.class) + private ReservationStatus status; + + @DateFormat + @Schema(description = "대여일자 시작일", example = "null") + private LocalDate startDate; + + @DateFormat + @Schema(description = "대여일자 종료일", example = "null") + private LocalDate endDate; +} diff --git a/src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationCustomRepository.java b/src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationCustomRepository.java new file mode 100644 index 0000000..29060fd --- /dev/null +++ b/src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationCustomRepository.java @@ -0,0 +1,12 @@ +package com.testcar.car.domains.carReservation.repository; + + +import com.testcar.car.domains.carReservation.model.dto.CarReservationDto; +import com.testcar.car.domains.carReservation.model.vo.CarReservationFilterCondition; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +public interface CarReservationCustomRepository { + Page findAllPageByCondition( + CarReservationFilterCondition condition, Pageable pageable); +} diff --git a/src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationCustomRepositoryImpl.java b/src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationCustomRepositoryImpl.java new file mode 100644 index 0000000..c07bebb --- /dev/null +++ b/src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationCustomRepositoryImpl.java @@ -0,0 +1,77 @@ +package com.testcar.car.domains.carReservation.repository; + +import static com.testcar.car.domains.carReservation.entity.QCarReservation.carReservation; + +import com.querydsl.core.types.OrderSpecifier; +import com.querydsl.core.types.Projections; +import com.querydsl.core.types.dsl.BooleanExpression; +import com.querydsl.jpa.impl.JPAQueryFactory; +import com.testcar.car.common.entity.BaseQueryDslRepository; +import com.testcar.car.domains.carReservation.entity.ReservationStatus; +import com.testcar.car.domains.carReservation.model.dto.CarReservationDto; +import com.testcar.car.domains.carReservation.model.vo.CarReservationFilterCondition; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.support.PageableExecutionUtils; + +@RequiredArgsConstructor +public class CarReservationCustomRepositoryImpl + implements CarReservationCustomRepository, BaseQueryDslRepository { + private final JPAQueryFactory jpaQueryFactory; + + @Override + public Page findAllPageByCondition( + CarReservationFilterCondition condition, Pageable pageable) { + final List coveringIndex = + jpaQueryFactory + .select(carReservation.id) + .from(carReservation) + .where( + notDeleted(carReservation), + carNameContainsOrNull(condition.getName()), + reservationStatusEqOrNull(condition.getStatus())) + .fetch(); + + final List carReservations = + jpaQueryFactory + .select( + Projections.constructor( + CarReservationDto.class, + carReservation, + carReservation.carStock.car.name, + carReservation.carStock.stockNumber)) + .from(carReservation) + .where(carReservation.id.in(coveringIndex)) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .orderBy( + getOrders( + carReservation, + pageable.getSort(), + orderByReservationStatus(), + carReservation.startedAt.desc())) + .fetch(); + return PageableExecutionUtils.getPage(carReservations, pageable, coveringIndex::size); + } + + private BooleanExpression carNameContainsOrNull(String name) { + return name == null ? null : carReservation.carStock.car.name.contains(name); + } + + private BooleanExpression reservationStatusEqOrNull(ReservationStatus status) { + return status == null ? null : carReservation.status.eq(status); + } + + private OrderSpecifier orderByReservationStatus() { + return carReservation + .status + .when(ReservationStatus.RESERVED) + .then(1) + .when(ReservationStatus.RETURNED) + .then(2) + .otherwise(3) + .asc(); + } +} diff --git a/src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationRepository.java b/src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationRepository.java new file mode 100644 index 0000000..f30381d --- /dev/null +++ b/src/main/java/com/testcar/car/domains/carReservation/repository/CarReservationRepository.java @@ -0,0 +1,8 @@ +package com.testcar.car.domains.carReservation.repository; + + +import com.testcar.car.domains.carReservation.entity.CarReservation; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface CarReservationRepository + extends JpaRepository, CarReservationCustomRepository {} diff --git a/src/main/java/com/testcar/car/domains/carStock/CarStockController.java b/src/main/java/com/testcar/car/domains/carStock/CarStockController.java index c55de30..6165225 100644 --- a/src/main/java/com/testcar/car/domains/carStock/CarStockController.java +++ b/src/main/java/com/testcar/car/domains/carStock/CarStockController.java @@ -3,6 +3,7 @@ import com.testcar.car.common.annotation.RoleAllowed; import com.testcar.car.common.response.PageResponse; +import com.testcar.car.domains.carStock.entity.CarStock; import com.testcar.car.domains.carStock.model.CarStockResponse; import com.testcar.car.domains.carStock.model.RegisterCarStockRequest; import com.testcar.car.domains.carStock.model.UpdateCarStockRequest; diff --git a/src/main/java/com/testcar/car/domains/carStock/CarStockService.java b/src/main/java/com/testcar/car/domains/carStock/CarStockService.java index 3a516d8..6f8cf0b 100644 --- a/src/main/java/com/testcar/car/domains/carStock/CarStockService.java +++ b/src/main/java/com/testcar/car/domains/carStock/CarStockService.java @@ -3,8 +3,9 @@ import com.testcar.car.common.exception.BadRequestException; import com.testcar.car.common.exception.NotFoundException; -import com.testcar.car.domains.car.Car; import com.testcar.car.domains.car.CarService; +import com.testcar.car.domains.car.entity.Car; +import com.testcar.car.domains.carStock.entity.CarStock; import com.testcar.car.domains.carStock.exception.ErrorCode; import com.testcar.car.domains.carStock.model.RegisterCarStockRequest; import com.testcar.car.domains.carStock.model.UpdateCarStockRequest; diff --git a/src/main/java/com/testcar/car/domains/carStock/CarStock.java b/src/main/java/com/testcar/car/domains/carStock/entity/CarStock.java similarity index 94% rename from src/main/java/com/testcar/car/domains/carStock/CarStock.java rename to src/main/java/com/testcar/car/domains/carStock/entity/CarStock.java index 83625a2..87ecd50 100644 --- a/src/main/java/com/testcar/car/domains/carStock/CarStock.java +++ b/src/main/java/com/testcar/car/domains/carStock/entity/CarStock.java @@ -1,8 +1,8 @@ -package com.testcar.car.domains.carStock; +package com.testcar.car.domains.carStock.entity; import com.testcar.car.common.entity.BaseEntity; -import com.testcar.car.domains.car.Car; +import com.testcar.car.domains.car.entity.Car; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; diff --git a/src/main/java/com/testcar/car/domains/carStock/StockStatus.java b/src/main/java/com/testcar/car/domains/carStock/entity/StockStatus.java similarity index 85% rename from src/main/java/com/testcar/car/domains/carStock/StockStatus.java rename to src/main/java/com/testcar/car/domains/carStock/entity/StockStatus.java index ef0c137..fe36b68 100644 --- a/src/main/java/com/testcar/car/domains/carStock/StockStatus.java +++ b/src/main/java/com/testcar/car/domains/carStock/entity/StockStatus.java @@ -1,4 +1,4 @@ -package com.testcar.car.domains.carStock; +package com.testcar.car.domains.carStock.entity; import lombok.Getter; diff --git a/src/main/java/com/testcar/car/domains/carStock/model/CarStockResponse.java b/src/main/java/com/testcar/car/domains/carStock/model/CarStockResponse.java index ea258cf..c1df605 100644 --- a/src/main/java/com/testcar/car/domains/carStock/model/CarStockResponse.java +++ b/src/main/java/com/testcar/car/domains/carStock/model/CarStockResponse.java @@ -1,8 +1,8 @@ package com.testcar.car.domains.carStock.model; -import com.testcar.car.domains.carStock.CarStock; -import com.testcar.car.domains.carStock.StockStatus; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.carStock.entity.StockStatus; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/com/testcar/car/domains/carStock/model/RegisterCarStockRequest.java b/src/main/java/com/testcar/car/domains/carStock/model/RegisterCarStockRequest.java index d900622..ef2516a 100644 --- a/src/main/java/com/testcar/car/domains/carStock/model/RegisterCarStockRequest.java +++ b/src/main/java/com/testcar/car/domains/carStock/model/RegisterCarStockRequest.java @@ -1,7 +1,7 @@ package com.testcar.car.domains.carStock.model; -import com.testcar.car.domains.carStock.StockStatus; +import com.testcar.car.domains.carStock.entity.StockStatus; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/testcar/car/domains/carStock/model/UpdateCarStockRequest.java b/src/main/java/com/testcar/car/domains/carStock/model/UpdateCarStockRequest.java index 0ea66e2..2405b68 100644 --- a/src/main/java/com/testcar/car/domains/carStock/model/UpdateCarStockRequest.java +++ b/src/main/java/com/testcar/car/domains/carStock/model/UpdateCarStockRequest.java @@ -1,7 +1,7 @@ package com.testcar.car.domains.carStock.model; -import com.testcar.car.domains.carStock.StockStatus; +import com.testcar.car.domains.carStock.entity.StockStatus; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/testcar/car/domains/carStock/model/vo/CarStockFilterCondition.java b/src/main/java/com/testcar/car/domains/carStock/model/vo/CarStockFilterCondition.java index 8485470..103575b 100644 --- a/src/main/java/com/testcar/car/domains/carStock/model/vo/CarStockFilterCondition.java +++ b/src/main/java/com/testcar/car/domains/carStock/model/vo/CarStockFilterCondition.java @@ -1,7 +1,7 @@ package com.testcar.car.domains.carStock.model.vo; -import com.testcar.car.domains.carStock.StockStatus; +import com.testcar.car.domains.carStock.entity.StockStatus; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Getter; import lombok.Setter; diff --git a/src/main/java/com/testcar/car/domains/carStock/repository/CarStockCustomRepository.java b/src/main/java/com/testcar/car/domains/carStock/repository/CarStockCustomRepository.java index ac4fe3c..3078c91 100644 --- a/src/main/java/com/testcar/car/domains/carStock/repository/CarStockCustomRepository.java +++ b/src/main/java/com/testcar/car/domains/carStock/repository/CarStockCustomRepository.java @@ -1,7 +1,7 @@ package com.testcar.car.domains.carStock.repository; -import com.testcar.car.domains.carStock.CarStock; +import com.testcar.car.domains.carStock.entity.CarStock; import com.testcar.car.domains.carStock.model.vo.CarStockFilterCondition; import java.util.Optional; import org.springframework.data.domain.Page; diff --git a/src/main/java/com/testcar/car/domains/carStock/repository/CarStockCustomRepositoryImpl.java b/src/main/java/com/testcar/car/domains/carStock/repository/CarStockCustomRepositoryImpl.java index eabcf23..e3821e8 100644 --- a/src/main/java/com/testcar/car/domains/carStock/repository/CarStockCustomRepositoryImpl.java +++ b/src/main/java/com/testcar/car/domains/carStock/repository/CarStockCustomRepositoryImpl.java @@ -1,14 +1,14 @@ package com.testcar.car.domains.carStock.repository; -import static com.testcar.car.domains.car.QCar.car; -import static com.testcar.car.domains.carStock.QCarStock.carStock; +import static com.testcar.car.domains.car.entity.QCar.car; +import static com.testcar.car.domains.carStock.entity.QCarStock.carStock; import com.querydsl.core.types.OrderSpecifier; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import com.testcar.car.common.entity.BaseQueryDslRepository; -import com.testcar.car.domains.carStock.CarStock; -import com.testcar.car.domains.carStock.StockStatus; +import com.testcar.car.domains.carStock.entity.CarStock; +import com.testcar.car.domains.carStock.entity.StockStatus; import com.testcar.car.domains.carStock.model.vo.CarStockFilterCondition; import java.util.List; import java.util.Optional; diff --git a/src/main/java/com/testcar/car/domains/carStock/repository/CarStockRepository.java b/src/main/java/com/testcar/car/domains/carStock/repository/CarStockRepository.java index 35ec830..66a1ef2 100644 --- a/src/main/java/com/testcar/car/domains/carStock/repository/CarStockRepository.java +++ b/src/main/java/com/testcar/car/domains/carStock/repository/CarStockRepository.java @@ -1,7 +1,7 @@ package com.testcar.car.domains.carStock.repository; -import com.testcar.car.domains.carStock.CarStock; +import com.testcar.car.domains.carStock.entity.CarStock; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/src/main/java/com/testcar/car/domains/carTest/CarTest.java b/src/main/java/com/testcar/car/domains/carTest/CarTest.java index a925e0d..e72a781 100644 --- a/src/main/java/com/testcar/car/domains/carTest/CarTest.java +++ b/src/main/java/com/testcar/car/domains/carTest/CarTest.java @@ -2,7 +2,7 @@ import com.testcar.car.common.entity.BaseEntity; -import com.testcar.car.domains.carStock.CarStock; +import com.testcar.car.domains.carStock.entity.CarStock; import com.testcar.car.domains.member.Member; import com.testcar.car.domains.track.Track; import jakarta.persistence.Column; diff --git a/src/main/java/com/testcar/car/domains/gasStationHistory/GasStationHistoryService.java b/src/main/java/com/testcar/car/domains/gasStationHistory/GasStationHistoryService.java index 72362d8..876cc99 100644 --- a/src/main/java/com/testcar/car/domains/gasStationHistory/GasStationHistoryService.java +++ b/src/main/java/com/testcar/car/domains/gasStationHistory/GasStationHistoryService.java @@ -2,8 +2,8 @@ import com.testcar.car.common.exception.NotFoundException; -import com.testcar.car.domains.carStock.CarStock; import com.testcar.car.domains.carStock.CarStockService; +import com.testcar.car.domains.carStock.entity.CarStock; import com.testcar.car.domains.gasStation.GasStationService; import com.testcar.car.domains.gasStation.entity.GasStation; import com.testcar.car.domains.gasStationHistory.entity.GasStationHistory; diff --git a/src/main/java/com/testcar/car/domains/gasStationHistory/entity/GasStationHistory.java b/src/main/java/com/testcar/car/domains/gasStationHistory/entity/GasStationHistory.java index 83cc2b3..73aa3e1 100644 --- a/src/main/java/com/testcar/car/domains/gasStationHistory/entity/GasStationHistory.java +++ b/src/main/java/com/testcar/car/domains/gasStationHistory/entity/GasStationHistory.java @@ -2,7 +2,7 @@ import com.testcar.car.common.entity.BaseEntity; -import com.testcar.car.domains.carStock.CarStock; +import com.testcar.car.domains.carStock.entity.CarStock; import com.testcar.car.domains.gasStation.entity.GasStation; import com.testcar.car.domains.member.Member; import jakarta.persistence.Column; diff --git a/src/main/resources/db/migration/V6__UpdateCarReservation.sql b/src/main/resources/db/migration/V6__UpdateCarReservation.sql new file mode 100644 index 0000000..2f887cb --- /dev/null +++ b/src/main/resources/db/migration/V6__UpdateCarReservation.sql @@ -0,0 +1,10 @@ +DROP INDEX `IDX_CAR_RESERVATION_RESERVED_AT` ON `CarReservation`; + +ALTER TABLE `CarReservation` + CHANGE COLUMN `reservedAt` `startedAt` DATETIME(6) NOT NULL COMMENT '예약 시작 시각'; + +ALTER TABLE `CarReservation` + ADD COLUMN `expiredAt` DATETIME(6) NOT NULL COMMENT '예약 종료 시각'; + +CREATE INDEX `IDX_CAR_RESERVATION_STARTED_AT` ON `CarReservation` (startedAt); +CREATE INDEX `IDX_CAR_RESERVATION_EXPIRED_AT` ON `CarReservation` (expiredAt);