From 9e1dfea17600ace820d066f56915bb3ea08b3a97 Mon Sep 17 00:00:00 2001 From: imdh Date: Thu, 24 Aug 2023 12:45:32 +0900 Subject: [PATCH] =?UTF-8?q?[Feature]=20=EB=AA=A8=EB=8D=B8=EC=97=90=20?= =?UTF-8?q?=ED=83=80=EC=9E=85,=20=EA=B0=80=EA=B2=A9=20=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80=20(#386)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 모델별 Type 추가 * feat: 모델 정보에 price, type 정보 추가 * feat: lazy loading을 위한 transactional 설정 * test: price, type 정보 추가에 따른 TC 수정 * feat: createAt, updatedAt 추가 * feat: 응답에 isNew 추가 최신형 차들 30일 기준으로 isNew 판단 * test: isNew 추가에 따른 TC 수정 --- .../model/dto/response/ModelDto.java | 23 ++++++++++++++++ .../get_models/GetModelsJpaAdaptor.java | 5 +++- .../be_my_car_master/domain/model/Model.java | 9 +++++++ .../be_my_car_master/domain/model/Type.java | 22 ++++++++++++++++ .../global/config/BaseTime.java | 24 +++++++++++++++++ .../jpa/model/entity/ModelEntity.java | 26 ++++++++++++++++++- .../model/repository/ModelJpaRepository.java | 4 +++ .../CreateEstimateUseCaseTest.java | 13 +++++++--- .../model/controller/ModelControllerTest.java | 3 +++ .../model/usecase/GetModelsUseCaseTest.java | 8 ++++++ 10 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 BE-MyCarMaster/src/main/java/softeer/be_my_car_master/domain/model/Type.java create mode 100644 BE-MyCarMaster/src/main/java/softeer/be_my_car_master/global/config/BaseTime.java diff --git a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/application/model/dto/response/ModelDto.java b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/application/model/dto/response/ModelDto.java index 71ca5068..3d6d7a79 100644 --- a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/application/model/dto/response/ModelDto.java +++ b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/application/model/dto/response/ModelDto.java @@ -1,5 +1,8 @@ package softeer.be_my_car_master.application.model.dto.response; +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; + import io.swagger.v3.oas.annotations.media.Schema; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -23,11 +26,31 @@ public class ModelDto { @Schema(description = "모델 이미지", example = "s3 url") private String imgUrl; + @Schema(description = "최소 가격", example = "100000") + private Integer price; + + @Schema(description = "타입", example = "SUV") + private String type; + + @Schema(description = "신 차 여부", example = "true") + private Boolean isNew; + public static ModelDto from(Model model) { + Boolean isNew = isNewModel(model); return ModelDto.builder() .id(model.getId()) .name(model.getName()) .imgUrl(model.getImgUrl()) + .price(model.getPrice()) + .type(model.getType()) + .isNew(isNew) .build(); } + + private static Boolean isNewModel(Model model) { + LocalDateTime createdAt = model.getCreatedAt(); + LocalDateTime now = LocalDateTime.now(); + long daysBetween = ChronoUnit.DAYS.between(createdAt, now); + return daysBetween < 30; + } } diff --git a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/application/model/usecase/get_models/GetModelsJpaAdaptor.java b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/application/model/usecase/get_models/GetModelsJpaAdaptor.java index 6b814f3e..e854fbf0 100644 --- a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/application/model/usecase/get_models/GetModelsJpaAdaptor.java +++ b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/application/model/usecase/get_models/GetModelsJpaAdaptor.java @@ -3,6 +3,8 @@ import java.util.List; import java.util.stream.Collectors; +import org.springframework.transaction.annotation.Transactional; + import lombok.RequiredArgsConstructor; import softeer.be_my_car_master.domain.model.Model; import softeer.be_my_car_master.global.annotation.Adaptor; @@ -16,8 +18,9 @@ public class GetModelsJpaAdaptor implements GetModelsPort { private final ModelJpaRepository modelJpaRepository; @Override + @Transactional(readOnly = true) public List findModels() { - return modelJpaRepository.findAll().stream() + return modelJpaRepository.findAllByOrderByCreatedAtDesc().stream() .map(ModelEntity::toModel) .collect(Collectors.toList()); } diff --git a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/domain/model/Model.java b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/domain/model/Model.java index d2ec5a3c..abaa06c3 100644 --- a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/domain/model/Model.java +++ b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/domain/model/Model.java @@ -1,5 +1,7 @@ package softeer.be_my_car_master.domain.model; +import java.time.LocalDateTime; + import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; @@ -14,8 +16,15 @@ public class Model { private final Long id; private final String name; private final String imgUrl; + private final Integer price; + private final Type type; + private final LocalDateTime createdAt; public boolean isRightModel(Long modelId) { return modelId.equals(id); } + + public String getType() { + return type.getValue(); + } } diff --git a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/domain/model/Type.java b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/domain/model/Type.java new file mode 100644 index 00000000..3bece4cc --- /dev/null +++ b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/domain/model/Type.java @@ -0,0 +1,22 @@ +package softeer.be_my_car_master.domain.model; + +import lombok.Getter; + +@Getter +public enum Type { + + HYDROGEN_ELECTRIC("수소 / 전기차"), + N("N"), + PASSENGER("승용차"), + SUV("SUV"), + MPV("MPV"), + LIGHT_TRUCK_AND_TAXI("소형 트럭&택시"), + TRUCK("트럭"), + BUS("버스"); + + private String value; + + Type(String value) { + this.value = value; + } +} diff --git a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/global/config/BaseTime.java b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/global/config/BaseTime.java new file mode 100644 index 00000000..af20fe75 --- /dev/null +++ b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/global/config/BaseTime.java @@ -0,0 +1,24 @@ +package softeer.be_my_car_master.global.config; + +import java.time.LocalDateTime; + +import javax.persistence.EntityListeners; +import javax.persistence.MappedSuperclass; + +import org.springframework.data.annotation.CreatedDate; +import org.springframework.data.annotation.LastModifiedDate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +import lombok.Getter; + +@Getter +@MappedSuperclass +@EntityListeners(AuditingEntityListener.class) +public abstract class BaseTime { + + @CreatedDate + protected LocalDateTime createdAt; + + @LastModifiedDate + protected LocalDateTime updatedAt; +} diff --git a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/infrastructure/jpa/model/entity/ModelEntity.java b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/infrastructure/jpa/model/entity/ModelEntity.java index 8b1531d0..a413fb8b 100644 --- a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/infrastructure/jpa/model/entity/ModelEntity.java +++ b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/infrastructure/jpa/model/entity/ModelEntity.java @@ -1,20 +1,29 @@ package softeer.be_my_car_master.infrastructure.jpa.model.entity; +import java.util.ArrayList; +import java.util.List; + import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; +import javax.persistence.OneToMany; import javax.persistence.Table; import lombok.AccessLevel; import lombok.NoArgsConstructor; import softeer.be_my_car_master.domain.model.Model; +import softeer.be_my_car_master.domain.model.Type; +import softeer.be_my_car_master.global.config.BaseTime; +import softeer.be_my_car_master.infrastructure.jpa.trim.entity.TrimEntity; @Entity @Table(name = "model") @NoArgsConstructor(access = AccessLevel.PROTECTED) -public class ModelEntity { +public class ModelEntity extends BaseTime { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -26,11 +35,26 @@ public class ModelEntity { @Column(name = "img_url", nullable = false) private String imgUrl; + @Column(name = "type", nullable = false) + @Enumerated(EnumType.STRING) + private Type type; + + @OneToMany(mappedBy = "model") + private List trims = new ArrayList<>(); + public Model toModel() { + Integer minPrice = trims.stream() + .map(TrimEntity::getPrice) + .min(Integer::compareTo) + .orElse(0); + return Model.builder() .id(id) .name(name) .imgUrl(imgUrl) + .type(type) + .price(minPrice) + .createdAt(createdAt) .build(); } } diff --git a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/infrastructure/jpa/model/repository/ModelJpaRepository.java b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/infrastructure/jpa/model/repository/ModelJpaRepository.java index bc45c5f8..1c6e252f 100644 --- a/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/infrastructure/jpa/model/repository/ModelJpaRepository.java +++ b/BE-MyCarMaster/src/main/java/softeer/be_my_car_master/infrastructure/jpa/model/repository/ModelJpaRepository.java @@ -1,8 +1,12 @@ package softeer.be_my_car_master.infrastructure.jpa.model.repository; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import softeer.be_my_car_master.infrastructure.jpa.model.entity.ModelEntity; public interface ModelJpaRepository extends JpaRepository { + + List findAllByOrderByCreatedAtDesc(); } diff --git a/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/estimate/usecase/create_estimate/CreateEstimateUseCaseTest.java b/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/estimate/usecase/create_estimate/CreateEstimateUseCaseTest.java index 9e52447f..cb2214f1 100644 --- a/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/estimate/usecase/create_estimate/CreateEstimateUseCaseTest.java +++ b/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/estimate/usecase/create_estimate/CreateEstimateUseCaseTest.java @@ -3,7 +3,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.BDDMockito.*; -import java.util.ArrayList; +import java.time.LocalDateTime; import java.util.Arrays; import java.util.UUID; @@ -24,6 +24,7 @@ import softeer.be_my_car_master.domain.color_interior.InteriorColor; import softeer.be_my_car_master.domain.engine.Engine; import softeer.be_my_car_master.domain.model.Model; +import softeer.be_my_car_master.domain.model.Type; import softeer.be_my_car_master.domain.option.Option; import softeer.be_my_car_master.domain.trim.Trim; import softeer.be_my_car_master.domain.wheel_dirve.WheelDrive; @@ -67,7 +68,10 @@ void execute() { .totalPrice(4000) .build(); - given(port.findModels()).willReturn(Arrays.asList(new Model(1L, "model", "url"))); + given(port.findModels()) + .willReturn(Arrays.asList( + new Model(1L, "model", "url", 100, Type.SUV, LocalDateTime.now()) + )); given(port.findTrimsByModel(any())) .willReturn(Arrays.asList( new Trim(1L, "model", "description", 22, 500, "url") @@ -167,7 +171,10 @@ void invalidOptions() { .totalPrice(4000) .build(); - given(port.findModels()).willReturn(Arrays.asList(new Model(1L, "model", "url"))); + given(port.findModels()) + .willReturn(Arrays.asList( + new Model(1L, "model", "url", 1000, Type.SUV, LocalDateTime.now()) + )); given(port.findTrimsByModel(any())) .willReturn(Arrays.asList( new Trim(1L, "model", "description", 22, 500, "url") diff --git a/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/model/controller/ModelControllerTest.java b/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/model/controller/ModelControllerTest.java index 18eab072..efffcc5d 100644 --- a/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/model/controller/ModelControllerTest.java +++ b/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/model/controller/ModelControllerTest.java @@ -19,6 +19,7 @@ import softeer.be_my_car_master.application.model.dto.response.GetModelsResponse; import softeer.be_my_car_master.application.model.dto.response.ModelDto; import softeer.be_my_car_master.application.model.usecase.get_models.GetModelsUseCase; +import softeer.be_my_car_master.domain.model.Type; import softeer.be_my_car_master.global.response.Response; @WebMvcTest(ModelController.class) @@ -42,6 +43,8 @@ void getModels() throws Exception { .id(1L) .name("model name") .imgUrl("imgUrl") + .price(1000) + .type(Type.SUV.getValue()) .build(); response.setModels(Arrays.asList(modelDto)); given(getModelsUseCase.execute()).willReturn(response); diff --git a/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/model/usecase/GetModelsUseCaseTest.java b/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/model/usecase/GetModelsUseCaseTest.java index 424a164a..55d9865b 100644 --- a/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/model/usecase/GetModelsUseCaseTest.java +++ b/BE-MyCarMaster/src/test/java/softeer/be_my_car_master/application/model/usecase/GetModelsUseCaseTest.java @@ -2,6 +2,7 @@ import static org.mockito.BDDMockito.*; +import java.time.LocalDateTime; import java.util.Arrays; import java.util.List; @@ -18,6 +19,7 @@ import softeer.be_my_car_master.application.model.usecase.get_models.GetModelsPort; import softeer.be_my_car_master.application.model.usecase.get_models.GetModelsUseCase; import softeer.be_my_car_master.domain.model.Model; +import softeer.be_my_car_master.domain.model.Type; @ExtendWith(MockitoExtension.class) @DisplayName("GetModelsUseCase Test") @@ -37,6 +39,9 @@ void execute() { .id(1L) .name("name") .imgUrl("image") + .price(10000) + .type(Type.SUV) + .createdAt(LocalDateTime.now()) .build(); given(getModelsPort.findModels()).willReturn(Arrays.asList(model)); @@ -53,6 +58,9 @@ void execute() { softAssertions.assertThat(expected.getId()).isEqualTo(model.getId()); softAssertions.assertThat(expected.getName()).isEqualTo(model.getName()); softAssertions.assertThat(expected.getImgUrl()).isEqualTo(model.getImgUrl()); + softAssertions.assertThat(expected.getPrice()).isEqualTo(model.getPrice()); + softAssertions.assertThat(expected.getType()).isEqualTo(model.getType()); + softAssertions.assertThat(expected.getIsNew()).isEqualTo(true); }); } }