From 011dd7e17608e168c94448fb1d8da30ee0a9ad1f Mon Sep 17 00:00:00 2001 From: "Chanmin Ju(Hu chu)" Date: Tue, 20 Feb 2024 16:14:01 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=83=81=ED=92=88=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20api=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=88=98=EC=A0=95=20(#92)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feature: ProductDescription 도메인 객체 추가 * chore: Rebase conflict 해결 * refactor: ProductDescription 없는 경우 반영하도록 수정 * refactor: ImageType 변수명 변경 * chore: 더미 데이터에 변경 내용 반영 * refactor: Description, Option, Info 의 외래키를 Product 가 관리하도록 변경 * refactor: Product 필드 기본값 수정 --- .../application/product/ProductService.kt | 20 +++- .../application/product/dto/ProductDtos.kt | 30 +++-- .../petqua/common/config/DataInitializer.kt | 104 +++++++++++------- .../com/petqua/domain/product/Product.kt | 20 ++-- .../domain/product/ProductCustomRepository.kt | 2 +- .../product/ProductCustomRepositoryImpl.kt | 17 ++- .../detail/description/ProductDescription.kt | 21 ++++ .../description/ProductDescriptionContent.kt | 10 ++ .../ProductDescriptionRepository.kt | 5 + .../description/ProductDescriptionTitle.kt | 10 ++ .../domain/product/detail/image/ImageType.kt | 10 ++ .../detail/{ => image}/ProductImage.kt | 8 +- .../{ => image}/ProductImageRepository.kt | 2 +- .../detail/{ => info}/DifficultyLevel.kt | 2 +- .../detail/{ => info}/OptimalTankSize.kt | 2 +- .../detail/{ => info}/OptimalTemperature.kt | 2 +- .../product/detail/{ => info}/ProductInfo.kt | 5 +- .../{ => info}/ProductInfoRepository.kt | 2 +- .../product/detail/{ => info}/Temperament.kt | 2 +- .../petqua/domain/product/dto/ProductDtos.kt | 14 ++- .../domain/product/option/ProductOption.kt | 3 - .../application/product/ProductServiceTest.kt | 64 +++++++---- .../ProductCustomRepositoryImplTest.kt | 103 +++++++++++++---- .../product/ProductControllerTest.kt | 65 +++++++---- .../petqua/test/fixture/ProductFixtures.kt | 79 ++++++++----- 25 files changed, 430 insertions(+), 172 deletions(-) create mode 100644 src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescription.kt create mode 100644 src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionContent.kt create mode 100644 src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionRepository.kt create mode 100644 src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionTitle.kt create mode 100644 src/main/kotlin/com/petqua/domain/product/detail/image/ImageType.kt rename src/main/kotlin/com/petqua/domain/product/detail/{ => image}/ProductImage.kt (68%) rename src/main/kotlin/com/petqua/domain/product/detail/{ => image}/ProductImageRepository.kt (81%) rename src/main/kotlin/com/petqua/domain/product/detail/{ => info}/DifficultyLevel.kt (72%) rename src/main/kotlin/com/petqua/domain/product/detail/{ => info}/OptimalTankSize.kt (76%) rename src/main/kotlin/com/petqua/domain/product/detail/{ => info}/OptimalTemperature.kt (84%) rename src/main/kotlin/com/petqua/domain/product/detail/{ => info}/ProductInfo.kt (89%) rename src/main/kotlin/com/petqua/domain/product/detail/{ => info}/ProductInfoRepository.kt (74%) rename src/main/kotlin/com/petqua/domain/product/detail/{ => info}/Temperament.kt (72%) diff --git a/src/main/kotlin/com/petqua/application/product/ProductService.kt b/src/main/kotlin/com/petqua/application/product/ProductService.kt index a61514a7..d6bc0131 100644 --- a/src/main/kotlin/com/petqua/application/product/ProductService.kt +++ b/src/main/kotlin/com/petqua/application/product/ProductService.kt @@ -10,7 +10,10 @@ import com.petqua.domain.auth.LoginMemberOrGuest import com.petqua.domain.keyword.ProductKeywordRepository import com.petqua.domain.product.ProductRepository import com.petqua.domain.product.WishProductRepository -import com.petqua.domain.product.detail.ProductImageRepository +import com.petqua.domain.product.detail.image.ImageType +import com.petqua.domain.product.detail.image.ImageType.DESCRIPTION +import com.petqua.domain.product.detail.image.ImageType.SAMPLE +import com.petqua.domain.product.detail.image.ProductImageRepository import com.petqua.domain.product.dto.ProductResponse import com.petqua.exception.product.ProductException import com.petqua.exception.product.ProductExceptionType.NOT_FOUND_PRODUCT @@ -31,13 +34,24 @@ class ProductService( val productWithInfo = productRepository.findProductWithInfoByIdOrThrow(productId) { ProductException(NOT_FOUND_PRODUCT) } - val imageUrls = productImageRepository.findProductImagesByProductId(productId).map { it.imageUrl } + + val imagesByType = getProductImagesGroupedByType(productId) val isWished = loginMemberOrGuest.isMember() && wishProductRepository.existsByProductIdAndMemberId( productId = productId, memberId = loginMemberOrGuest.memberId ) - return ProductDetailResponse(productWithInfo, imageUrls, isWished) + return ProductDetailResponse( + productWithInfoResponse = productWithInfo, + imageUrls = imagesByType[SAMPLE] ?: emptyList(), + descriptionImageUrls = imagesByType[DESCRIPTION] ?: emptyList(), + isWished = isWished + ) + } + + private fun getProductImagesGroupedByType(productId: Long): Map> { + return productImageRepository.findProductImagesByProductId(productId).groupBy { it.imageType } + .mapValues { it.value.map { productImage -> productImage.imageUrl } } } @Transactional(readOnly = true) diff --git a/src/main/kotlin/com/petqua/application/product/dto/ProductDtos.kt b/src/main/kotlin/com/petqua/application/product/dto/ProductDtos.kt index 96716c5b..872e91eb 100644 --- a/src/main/kotlin/com/petqua/application/product/dto/ProductDtos.kt +++ b/src/main/kotlin/com/petqua/application/product/dto/ProductDtos.kt @@ -83,12 +83,6 @@ data class ProductDetailResponse( ) val reviewAverageScore: Double, - @Schema( - description = "상품 썸네일 이미지", - example = "https://docs.petqua.co.kr/products/thumbnails/thumbnail1.jpeg" - ) - val thumbnailUrl: String, - @Schema( description = "상품 이미지 목록", example = "[image1.jpeg, image2.jpeg]" @@ -96,10 +90,22 @@ data class ProductDetailResponse( val imageUrls: List, @Schema( - description = "상품 상세 설명", - example = "귀엽습니다" + description = "상품 상세 설명 제목", + example = "물생활 핵 인싸어, 레드 브론즈 구피" + ) + val descriptionTitle: String, + + @Schema( + description = "상품 상세 설명 내용", + example = "레드 턱시도라고도 불리며 지느러미가 아름다운 구피입니다" + ) + val descriptionContent: String, + + @Schema( + description = "상품 상세 이미지", + example = "[image1.jpeg, image2.jpeg]" ) - val description: String, + val descriptionImageUrls: List, @Schema( description = "안전 배송 가능 여부", @@ -164,6 +170,7 @@ data class ProductDetailResponse( constructor( productWithInfoResponse: ProductWithInfoResponse, imageUrls: List, + descriptionImageUrls: List, isWished: Boolean, ) : this( id = productWithInfoResponse.id, @@ -177,9 +184,10 @@ data class ProductDetailResponse( wishCount = productWithInfoResponse.wishCount, reviewCount = productWithInfoResponse.reviewCount, reviewAverageScore = productWithInfoResponse.reviewAverageScore, - thumbnailUrl = productWithInfoResponse.thumbnailUrl, - description = productWithInfoResponse.description, imageUrls = imageUrls, + descriptionTitle = productWithInfoResponse.descriptionTitle, + descriptionContent = productWithInfoResponse.descriptionContent, + descriptionImageUrls = descriptionImageUrls, canDeliverSafely = productWithInfoResponse.canDeliverSafely, canDeliverCommonly = productWithInfoResponse.canDeliverCommonly, canPickUp = productWithInfoResponse.canPickUp, diff --git a/src/main/kotlin/com/petqua/common/config/DataInitializer.kt b/src/main/kotlin/com/petqua/common/config/DataInitializer.kt index 229d9097..57fc136e 100644 --- a/src/main/kotlin/com/petqua/common/config/DataInitializer.kt +++ b/src/main/kotlin/com/petqua/common/config/DataInitializer.kt @@ -18,14 +18,20 @@ import com.petqua.domain.product.category.Category import com.petqua.domain.product.category.CategoryRepository import com.petqua.domain.product.category.Family import com.petqua.domain.product.category.Species -import com.petqua.domain.product.detail.DifficultyLevel.NORMAL -import com.petqua.domain.product.detail.OptimalTankSize.TANK2 -import com.petqua.domain.product.detail.OptimalTemperature -import com.petqua.domain.product.detail.ProductImage -import com.petqua.domain.product.detail.ProductImageRepository -import com.petqua.domain.product.detail.ProductInfo -import com.petqua.domain.product.detail.ProductInfoRepository -import com.petqua.domain.product.detail.Temperament.PEACEFUL +import com.petqua.domain.product.detail.description.ProductDescription +import com.petqua.domain.product.detail.description.ProductDescriptionContent +import com.petqua.domain.product.detail.description.ProductDescriptionRepository +import com.petqua.domain.product.detail.description.ProductDescriptionTitle +import com.petqua.domain.product.detail.image.ImageType.DESCRIPTION +import com.petqua.domain.product.detail.image.ImageType.SAMPLE +import com.petqua.domain.product.detail.image.ProductImage +import com.petqua.domain.product.detail.image.ProductImageRepository +import com.petqua.domain.product.detail.info.DifficultyLevel.NORMAL +import com.petqua.domain.product.detail.info.OptimalTankSize.TANK2 +import com.petqua.domain.product.detail.info.OptimalTemperature +import com.petqua.domain.product.detail.info.ProductInfo +import com.petqua.domain.product.detail.info.ProductInfoRepository +import com.petqua.domain.product.detail.info.Temperament.PEACEFUL import com.petqua.domain.product.option.ProductOption import com.petqua.domain.product.option.ProductOptionRepository import com.petqua.domain.product.option.Sex.FEMALE @@ -46,6 +52,7 @@ import org.springframework.context.annotation.Profile import org.springframework.context.event.EventListener import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional +import kotlin.random.Random @Component @Profile("local", "prod") @@ -64,6 +71,7 @@ class DataInitializer( private val productOptionRepository: ProductOptionRepository, private val wishProductRepository: WishProductRepository, private val productKeywordRepository: ProductKeywordRepository, + private val productDescriptionRepository: ProductDescriptionRepository, ) { @EventListener(ApplicationReadyEvent::class) @@ -164,6 +172,39 @@ class DataInitializer( } val reviewCount = (1..5).random() + val sex = when { + (it % 3) == 0 -> MALE + (it % 7) == 0 -> FEMALE + else -> HERMAPHRODITE + } + val productOption = productOptionRepository.save( + ProductOption( + sex = sex, + additionalPrice = BigDecimal.ZERO + ) + ) + + val productInfo = productInfoRepository.save( + ProductInfo( + categoryId = categoryId, + optimalTemperature = OptimalTemperature(22, 25), + difficultyLevel = NORMAL, + optimalTankSize = TANK2, + temperament = PEACEFUL + ) + ) + + val productDescriptionId = when { + (it % 4) != 0 -> productDescriptionRepository.save( + ProductDescription( + title = ProductDescriptionTitle("물생활 핵 인싸어, 상품$it"), + content = ProductDescriptionContent("지느러미가 아름다운 상품$it 입니다") + ) + ).id + + else -> null + } + Product( name = "상품$it", categoryId = categoryId, @@ -175,10 +216,12 @@ class DataInitializer( reviewCount = reviewCount, reviewTotalScore = (1..reviewCount).sum(), thumbnailUrl = "https://docs.petqua.co.kr/products/thumbnails/thumbnail3.jpeg", - description = "https://www.goldmoonaqua.com/web/upload/NNEditor/20221226/copy-1672038777-guppy_EC958CEBB984EB85B8ED9280EBA088EB939C_02.png", canDeliverSafely = canDeliverSafely, canDeliverCommonly = canDeliverCommonly, canPickUp = canPickUp, + productOptionId = productOption.id, + productDescriptionId = productDescriptionId, + productInfoId = productInfo.id, ) } productRepository.saveAll(products) @@ -213,42 +256,27 @@ class DataInitializer( } recommendationRepository.saveAll(productRecommendations) - // productOption - val productOptions = products.map { - val sex = when { - (it.id % 3).toInt() == 0 -> MALE - (it.id % 7).toInt() == 0 -> HERMAPHRODITE - else -> FEMALE + // productImage + val productImages = products.flatMap { product -> + List(Random.nextInt(1, 6)) { + ProductImage( + productId = product.id, + imageUrl = "https://docs.petqua.co.kr/products/thumbnails/thumbnail3.jpeg", + imageType = SAMPLE + ) } - ProductOption( - productId = it.id, - sex = sex, - additionalPrice = BigDecimal.ZERO - ) - } - productOptionRepository.saveAll(productOptions) - - // productInfo - val productInfos = products.map { - ProductInfo( - productId = it.id, - categoryId = it.categoryId, - optimalTemperature = OptimalTemperature(22, 25), - difficultyLevel = NORMAL, - optimalTankSize = TANK2, - temperament = PEACEFUL - ) } - productInfoRepository.saveAll(productInfos) + productImageRepository.saveAll(productImages) - // productImage - val productImages = products.map { + // productDescriptionImage + val productDescriptionImages = products.map { ProductImage( productId = it.id, - imageUrl = "https://docs.petqua.co.kr/products/thumbnails/thumbnail3.jpeg" + imageUrl = "https://www.goldmoonaqua.com/web/upload/NNEditor/20221226/copy-1672038777-guppy_EC958CEBB984EB85B8ED9280EBA088EB939C_02.png", + imageType = DESCRIPTION ) } - productImageRepository.saveAll(productImages) + productImageRepository.saveAll(productDescriptionImages) // review val productReviews = products.flatMap { product -> diff --git a/src/main/kotlin/com/petqua/domain/product/Product.kt b/src/main/kotlin/com/petqua/domain/product/Product.kt index 50ec1a28..71e30b9b 100644 --- a/src/main/kotlin/com/petqua/domain/product/Product.kt +++ b/src/main/kotlin/com/petqua/domain/product/Product.kt @@ -14,9 +14,6 @@ import jakarta.persistence.GenerationType import jakarta.persistence.Id import java.math.BigDecimal -private const val SCALE = 1 -private const val ZERO = 0 - @Entity class Product( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @@ -26,13 +23,13 @@ class Product( val name: String, @Column(nullable = false) - val categoryId: Long = 0, + val categoryId: Long, @Column(nullable = false) val price: BigDecimal, @Column(nullable = false) - val storeId: Long = 0, + val storeId: Long, @Column(nullable = false) val discountRate: Int = 0, @@ -53,9 +50,6 @@ class Product( @Column(nullable = false) val thumbnailUrl: String, - @Column(nullable = false) - val description: String, - @Column(nullable = false) var isDeleted: Boolean = false, @@ -67,6 +61,14 @@ class Product( @Column(nullable = false) val canPickUp: Boolean, + + @Column(nullable = false) + val productOptionId: Long, + + val productDescriptionId: Long?, + + @Column(nullable = false) + val productInfoId: Long, ) : BaseEntity(), SoftDeleteEntity { fun averageReviewScore(): Double { @@ -88,6 +90,6 @@ class Product( } override fun toString(): String { - return "Product(id=$id, name='$name', categoryId=$categoryId, price=$price, storeId=$storeId, discountRate=$discountRate, discountPrice=$discountPrice, wishCount=$wishCount, reviewCount=$reviewCount, reviewTotalScore=$reviewTotalScore, thumbnailUrl='$thumbnailUrl', description='$description', isDeleted=$isDeleted, canDeliverSafely=$canDeliverSafely, canDeliverCommonly=$canDeliverCommonly, canPickUp=$canPickUp)" + return "Product(id=$id, name='$name', categoryId=$categoryId, price=$price, storeId=$storeId, discountRate=$discountRate, discountPrice=$discountPrice, wishCount=$wishCount, reviewCount=$reviewCount, reviewTotalScore=$reviewTotalScore, thumbnailUrl='$thumbnailUrl', isDeleted=$isDeleted, canDeliverSafely=$canDeliverSafely, canDeliverCommonly=$canDeliverCommonly, canPickUp=$canPickUp)" } } diff --git a/src/main/kotlin/com/petqua/domain/product/ProductCustomRepository.kt b/src/main/kotlin/com/petqua/domain/product/ProductCustomRepository.kt index 16e3b7ac..70691609 100644 --- a/src/main/kotlin/com/petqua/domain/product/ProductCustomRepository.kt +++ b/src/main/kotlin/com/petqua/domain/product/ProductCustomRepository.kt @@ -3,8 +3,8 @@ package com.petqua.domain.product import com.petqua.common.domain.dto.CursorBasedPaging import com.petqua.domain.product.dto.ProductReadCondition import com.petqua.domain.product.dto.ProductResponse -import com.petqua.domain.product.dto.ProductWithInfoResponse import com.petqua.domain.product.dto.ProductSearchCondition +import com.petqua.domain.product.dto.ProductWithInfoResponse interface ProductCustomRepository { diff --git a/src/main/kotlin/com/petqua/domain/product/ProductCustomRepositoryImpl.kt b/src/main/kotlin/com/petqua/domain/product/ProductCustomRepositoryImpl.kt index 305395e6..587bc1a6 100644 --- a/src/main/kotlin/com/petqua/domain/product/ProductCustomRepositoryImpl.kt +++ b/src/main/kotlin/com/petqua/domain/product/ProductCustomRepositoryImpl.kt @@ -10,7 +10,11 @@ import com.petqua.common.util.createSingleQueryOrThrow import com.petqua.domain.keyword.ProductKeyword import com.petqua.domain.product.Sorter.ENROLLMENT_DATE_DESC import com.petqua.domain.product.category.Category -import com.petqua.domain.product.detail.ProductInfo +import com.petqua.domain.product.detail.description.ProductDescription +import com.petqua.domain.product.detail.description.ProductDescriptionContent +import com.petqua.domain.product.detail.description.ProductDescriptionTitle +import com.petqua.domain.product.detail.info.ProductInfo +import com.petqua.domain.product.dto.ProductDescriptionResponse import com.petqua.domain.product.dto.ProductReadCondition import com.petqua.domain.product.dto.ProductResponse import com.petqua.domain.product.dto.ProductSearchCondition @@ -21,6 +25,7 @@ import jakarta.persistence.EntityManager import org.springframework.stereotype.Repository private const val ESCAPE_LETTER = '\\' +private const val EMPTY_VALUE = "" @Repository class ProductCustomRepositoryImpl( @@ -37,15 +42,21 @@ class ProductCustomRepositoryImpl( selectNew( entity(Product::class), path(Store::name), + new( + ProductDescriptionResponse::class, + coalesce(path(ProductDescription::title)(ProductDescriptionTitle::value), EMPTY_VALUE), + coalesce(path(ProductDescription::content)(ProductDescriptionContent::value), EMPTY_VALUE) + ), entity(ProductInfo::class), entity(Category::class), entity(ProductOption::class), ).from( entity(Product::class), join(Store::class).on(path(Product::storeId).eq(path(Store::id))), - join(ProductInfo::class).on(path(Product::id).eq(path(ProductInfo::productId))), + leftJoin(ProductDescription::class).on(path(Product::productDescriptionId).eq(path(ProductDescription::id))), + join(ProductInfo::class).on(path(Product::productInfoId).eq(path(ProductInfo::id))), join(Category::class).on(path(Product::categoryId).eq(path(Category::id))), - join(ProductOption::class).on(path(Product::id).eq(path(ProductOption::productId))) + join(ProductOption::class).on(path(Product::productOptionId).eq(path(ProductOption::id))) ).whereAnd( path(Product::id).eq(id), active(), diff --git a/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescription.kt b/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescription.kt new file mode 100644 index 00000000..0c8a8887 --- /dev/null +++ b/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescription.kt @@ -0,0 +1,21 @@ +package com.petqua.domain.product.detail.description + +import com.petqua.common.domain.BaseEntity +import jakarta.persistence.Embedded +import jakarta.persistence.Entity +import jakarta.persistence.GeneratedValue +import jakarta.persistence.GenerationType.IDENTITY +import jakarta.persistence.Id + +@Entity +class ProductDescription( + @Id @GeneratedValue(strategy = IDENTITY) + val id: Long = 0, + + @Embedded + val title: ProductDescriptionTitle, + + @Embedded + val content: ProductDescriptionContent, +) : BaseEntity() { +} diff --git a/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionContent.kt b/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionContent.kt new file mode 100644 index 00000000..5137baf1 --- /dev/null +++ b/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionContent.kt @@ -0,0 +1,10 @@ +package com.petqua.domain.product.detail.description + +import jakarta.persistence.Column +import jakarta.persistence.Embeddable + +@Embeddable +data class ProductDescriptionContent( + @Column(nullable = false, name = "content") + val value: String, +) diff --git a/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionRepository.kt b/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionRepository.kt new file mode 100644 index 00000000..7a5ecf7c --- /dev/null +++ b/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionRepository.kt @@ -0,0 +1,5 @@ +package com.petqua.domain.product.detail.description + +import org.springframework.data.jpa.repository.JpaRepository + +interface ProductDescriptionRepository : JpaRepository diff --git a/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionTitle.kt b/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionTitle.kt new file mode 100644 index 00000000..b5d8b482 --- /dev/null +++ b/src/main/kotlin/com/petqua/domain/product/detail/description/ProductDescriptionTitle.kt @@ -0,0 +1,10 @@ +package com.petqua.domain.product.detail.description + +import jakarta.persistence.Column +import jakarta.persistence.Embeddable + +@Embeddable +data class ProductDescriptionTitle( + @Column(nullable = false, name = "title") + val value: String, +) diff --git a/src/main/kotlin/com/petqua/domain/product/detail/image/ImageType.kt b/src/main/kotlin/com/petqua/domain/product/detail/image/ImageType.kt new file mode 100644 index 00000000..70c1ecb9 --- /dev/null +++ b/src/main/kotlin/com/petqua/domain/product/detail/image/ImageType.kt @@ -0,0 +1,10 @@ +package com.petqua.domain.product.detail.image + +enum class ImageType( + val description: String, +) { + + SAMPLE("상품 예시 이미지"), + DESCRIPTION("상품 상세 정보 이미지"), + ; +} diff --git a/src/main/kotlin/com/petqua/domain/product/detail/ProductImage.kt b/src/main/kotlin/com/petqua/domain/product/detail/image/ProductImage.kt similarity index 68% rename from src/main/kotlin/com/petqua/domain/product/detail/ProductImage.kt rename to src/main/kotlin/com/petqua/domain/product/detail/image/ProductImage.kt index 8b0c7749..52b95a8c 100644 --- a/src/main/kotlin/com/petqua/domain/product/detail/ProductImage.kt +++ b/src/main/kotlin/com/petqua/domain/product/detail/image/ProductImage.kt @@ -1,8 +1,10 @@ -package com.petqua.domain.product.detail +package com.petqua.domain.product.detail.image import com.petqua.common.domain.BaseEntity import jakarta.persistence.Column import jakarta.persistence.Entity +import jakarta.persistence.EnumType.STRING +import jakarta.persistence.Enumerated import jakarta.persistence.GeneratedValue import jakarta.persistence.GenerationType.IDENTITY import jakarta.persistence.Id @@ -17,4 +19,8 @@ class ProductImage( @Column(nullable = false) val imageUrl: String, + + @Column(nullable = false) + @Enumerated(STRING) + val imageType: ImageType, ) : BaseEntity() diff --git a/src/main/kotlin/com/petqua/domain/product/detail/ProductImageRepository.kt b/src/main/kotlin/com/petqua/domain/product/detail/image/ProductImageRepository.kt similarity index 81% rename from src/main/kotlin/com/petqua/domain/product/detail/ProductImageRepository.kt rename to src/main/kotlin/com/petqua/domain/product/detail/image/ProductImageRepository.kt index b4ccce02..deefae24 100644 --- a/src/main/kotlin/com/petqua/domain/product/detail/ProductImageRepository.kt +++ b/src/main/kotlin/com/petqua/domain/product/detail/image/ProductImageRepository.kt @@ -1,4 +1,4 @@ -package com.petqua.domain.product.detail +package com.petqua.domain.product.detail.image import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/com/petqua/domain/product/detail/DifficultyLevel.kt b/src/main/kotlin/com/petqua/domain/product/detail/info/DifficultyLevel.kt similarity index 72% rename from src/main/kotlin/com/petqua/domain/product/detail/DifficultyLevel.kt rename to src/main/kotlin/com/petqua/domain/product/detail/info/DifficultyLevel.kt index 54ee4eb2..756fe4c2 100644 --- a/src/main/kotlin/com/petqua/domain/product/detail/DifficultyLevel.kt +++ b/src/main/kotlin/com/petqua/domain/product/detail/info/DifficultyLevel.kt @@ -1,4 +1,4 @@ -package com.petqua.domain.product.detail +package com.petqua.domain.product.detail.info enum class DifficultyLevel( val description: String, diff --git a/src/main/kotlin/com/petqua/domain/product/detail/OptimalTankSize.kt b/src/main/kotlin/com/petqua/domain/product/detail/info/OptimalTankSize.kt similarity index 76% rename from src/main/kotlin/com/petqua/domain/product/detail/OptimalTankSize.kt rename to src/main/kotlin/com/petqua/domain/product/detail/info/OptimalTankSize.kt index cbfd7fb1..e079d2e9 100644 --- a/src/main/kotlin/com/petqua/domain/product/detail/OptimalTankSize.kt +++ b/src/main/kotlin/com/petqua/domain/product/detail/info/OptimalTankSize.kt @@ -1,4 +1,4 @@ -package com.petqua.domain.product.detail +package com.petqua.domain.product.detail.info enum class OptimalTankSize( diff --git a/src/main/kotlin/com/petqua/domain/product/detail/OptimalTemperature.kt b/src/main/kotlin/com/petqua/domain/product/detail/info/OptimalTemperature.kt similarity index 84% rename from src/main/kotlin/com/petqua/domain/product/detail/OptimalTemperature.kt rename to src/main/kotlin/com/petqua/domain/product/detail/info/OptimalTemperature.kt index d6619698..f5e160d1 100644 --- a/src/main/kotlin/com/petqua/domain/product/detail/OptimalTemperature.kt +++ b/src/main/kotlin/com/petqua/domain/product/detail/info/OptimalTemperature.kt @@ -1,4 +1,4 @@ -package com.petqua.domain.product.detail +package com.petqua.domain.product.detail.info import jakarta.persistence.Column import jakarta.persistence.Embeddable diff --git a/src/main/kotlin/com/petqua/domain/product/detail/ProductInfo.kt b/src/main/kotlin/com/petqua/domain/product/detail/info/ProductInfo.kt similarity index 89% rename from src/main/kotlin/com/petqua/domain/product/detail/ProductInfo.kt rename to src/main/kotlin/com/petqua/domain/product/detail/info/ProductInfo.kt index 2e2a263b..9552c301 100644 --- a/src/main/kotlin/com/petqua/domain/product/detail/ProductInfo.kt +++ b/src/main/kotlin/com/petqua/domain/product/detail/info/ProductInfo.kt @@ -1,4 +1,4 @@ -package com.petqua.domain.product.detail +package com.petqua.domain.product.detail.info import com.petqua.common.domain.BaseEntity import jakarta.persistence.Column @@ -15,9 +15,6 @@ class ProductInfo( @Id @GeneratedValue(strategy = IDENTITY) val id: Long = 0L, - @Column(nullable = false) - val productId: Long, - @Column(nullable = false) val categoryId: Long, diff --git a/src/main/kotlin/com/petqua/domain/product/detail/ProductInfoRepository.kt b/src/main/kotlin/com/petqua/domain/product/detail/info/ProductInfoRepository.kt similarity index 74% rename from src/main/kotlin/com/petqua/domain/product/detail/ProductInfoRepository.kt rename to src/main/kotlin/com/petqua/domain/product/detail/info/ProductInfoRepository.kt index a623d40b..cab73b88 100644 --- a/src/main/kotlin/com/petqua/domain/product/detail/ProductInfoRepository.kt +++ b/src/main/kotlin/com/petqua/domain/product/detail/info/ProductInfoRepository.kt @@ -1,4 +1,4 @@ -package com.petqua.domain.product.detail +package com.petqua.domain.product.detail.info import org.springframework.data.jpa.repository.JpaRepository diff --git a/src/main/kotlin/com/petqua/domain/product/detail/Temperament.kt b/src/main/kotlin/com/petqua/domain/product/detail/info/Temperament.kt similarity index 72% rename from src/main/kotlin/com/petqua/domain/product/detail/Temperament.kt rename to src/main/kotlin/com/petqua/domain/product/detail/info/Temperament.kt index 538012a7..c05e09a3 100644 --- a/src/main/kotlin/com/petqua/domain/product/detail/Temperament.kt +++ b/src/main/kotlin/com/petqua/domain/product/detail/info/Temperament.kt @@ -1,4 +1,4 @@ -package com.petqua.domain.product.detail +package com.petqua.domain.product.detail.info enum class Temperament( val description: String, diff --git a/src/main/kotlin/com/petqua/domain/product/dto/ProductDtos.kt b/src/main/kotlin/com/petqua/domain/product/dto/ProductDtos.kt index df2ecbee..14707a80 100644 --- a/src/main/kotlin/com/petqua/domain/product/dto/ProductDtos.kt +++ b/src/main/kotlin/com/petqua/domain/product/dto/ProductDtos.kt @@ -6,7 +6,7 @@ import com.petqua.domain.product.Product import com.petqua.domain.product.ProductSourceType import com.petqua.domain.product.Sorter import com.petqua.domain.product.category.Category -import com.petqua.domain.product.detail.ProductInfo +import com.petqua.domain.product.detail.info.ProductInfo import com.petqua.domain.product.option.ProductOption import com.petqua.exception.product.ProductException import com.petqua.exception.product.ProductExceptionType @@ -71,7 +71,8 @@ data class ProductWithInfoResponse( val reviewCount: Int, val reviewAverageScore: Double, val thumbnailUrl: String, - val description: String, + val descriptionTitle: String, + val descriptionContent: String, val canDeliverSafely: Boolean, val canDeliverCommonly: Boolean, val canPickUp: Boolean, @@ -85,6 +86,7 @@ data class ProductWithInfoResponse( constructor( product: Product, storeName: String, + productDescription: ProductDescriptionResponse, productInfo: ProductInfo, category: Category, productOption: ProductOption, @@ -101,7 +103,8 @@ data class ProductWithInfoResponse( reviewCount = product.reviewCount, reviewAverageScore = product.averageReviewScore(), thumbnailUrl = product.thumbnailUrl, - description = product.description, + descriptionTitle = productDescription.title, + descriptionContent = productDescription.content, canDeliverSafely = product.canDeliverSafely, canDeliverCommonly = product.canDeliverCommonly, canPickUp = product.canPickUp, @@ -114,6 +117,11 @@ data class ProductWithInfoResponse( ) } +data class ProductDescriptionResponse( + val title: String, + val content: String, +) + data class ProductResponse( @Schema( description = "상품 Id", diff --git a/src/main/kotlin/com/petqua/domain/product/option/ProductOption.kt b/src/main/kotlin/com/petqua/domain/product/option/ProductOption.kt index c34c3f1c..50205501 100644 --- a/src/main/kotlin/com/petqua/domain/product/option/ProductOption.kt +++ b/src/main/kotlin/com/petqua/domain/product/option/ProductOption.kt @@ -15,9 +15,6 @@ class ProductOption( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) val id: Long = 0L, - @Column(nullable = false) - val productId: Long, - @Column(nullable = false) @Enumerated(STRING) val sex: Sex, diff --git a/src/test/kotlin/com/petqua/application/product/ProductServiceTest.kt b/src/test/kotlin/com/petqua/application/product/ProductServiceTest.kt index ca69b48a..879f2fec 100644 --- a/src/test/kotlin/com/petqua/application/product/ProductServiceTest.kt +++ b/src/test/kotlin/com/petqua/application/product/ProductServiceTest.kt @@ -15,12 +15,15 @@ import com.petqua.domain.product.ProductSourceType.NONE import com.petqua.domain.product.Sorter.ENROLLMENT_DATE_DESC import com.petqua.domain.product.WishProductRepository import com.petqua.domain.product.category.CategoryRepository -import com.petqua.domain.product.detail.DifficultyLevel -import com.petqua.domain.product.detail.OptimalTankSize -import com.petqua.domain.product.detail.OptimalTemperature -import com.petqua.domain.product.detail.ProductImageRepository -import com.petqua.domain.product.detail.ProductInfoRepository -import com.petqua.domain.product.detail.Temperament +import com.petqua.domain.product.detail.description.ProductDescriptionRepository +import com.petqua.domain.product.detail.image.ImageType.DESCRIPTION +import com.petqua.domain.product.detail.image.ImageType.SAMPLE +import com.petqua.domain.product.detail.image.ProductImageRepository +import com.petqua.domain.product.detail.info.DifficultyLevel +import com.petqua.domain.product.detail.info.OptimalTankSize +import com.petqua.domain.product.detail.info.OptimalTemperature +import com.petqua.domain.product.detail.info.ProductInfoRepository +import com.petqua.domain.product.detail.info.Temperament import com.petqua.domain.product.option.ProductOptionRepository import com.petqua.domain.product.option.Sex.FEMALE import com.petqua.domain.store.StoreRepository @@ -30,6 +33,7 @@ import com.petqua.test.DataCleaner import com.petqua.test.fixture.category import com.petqua.test.fixture.member import com.petqua.test.fixture.product +import com.petqua.test.fixture.productDescription import com.petqua.test.fixture.productDetailResponse import com.petqua.test.fixture.productImage import com.petqua.test.fixture.productInfo @@ -58,6 +62,7 @@ class ProductServiceTest( private val wishProductRepository: WishProductRepository, private val categoryRepository: CategoryRepository, private val productOptionRepository: ProductOptionRepository, + private val productDescriptionRepository: ProductDescriptionRepository, private val dataCleaner: DataCleaner, ) : BehaviorSpec({ @@ -72,36 +77,51 @@ class ProductServiceTest( species = "고정구피" ) ) - val product = productRepository.save( - product( - name = "고정구피", - storeId = store.id, - categoryId = category.id, - discountPrice = BigDecimal.ZERO, - reviewCount = 0, - reviewTotalScore = 0 + val productDescription = productDescriptionRepository.save( + productDescription( + title = "물생활 핵 인싸어, 레드 브론즈 구피", + content = "레드 턱시도라고도 불리며 지느러미가 아름다운 구피입니다" ) ) val productInfo = productInfoRepository.save( productInfo( - productId = product.id, - categoryId = 0, + categoryId = category.id, optimalTemperature = OptimalTemperature(26, 28), difficultyLevel = DifficultyLevel.EASY, optimalTankSize = OptimalTankSize.TANK1, temperament = Temperament.PEACEFUL, ) ) + val productOption = productOptionRepository.save( + productOption( + sex = FEMALE, + ) + ) + val product = productRepository.save( + product( + name = "고정구피", + storeId = store.id, + categoryId = category.id, + discountPrice = BigDecimal.ZERO, + reviewCount = 0, + reviewTotalScore = 0, + productOptionId = productOption.id, + productDescriptionId = productDescription.id, + productInfoId = productInfo.id, + ) + ) val productImage = productImageRepository.save( productImage( productId = product.id, - imageUrl = "image.jpeg" + imageUrl = "image.jpeg", + imageType = SAMPLE ) ) - val productOption = productOptionRepository.save( - productOption( + val productDescriptionImage = productImageRepository.save( + productImage( productId = product.id, - sex = FEMALE, + imageUrl = "image.jpeg", + imageType = DESCRIPTION ) ) wishProductRepository.save( @@ -122,6 +142,8 @@ class ProductServiceTest( product = product, storeName = store.name, imageUrls = listOf(productImage.imageUrl), + productDescription = productDescription, + descriptionImageUrls = listOf(productDescriptionImage.imageUrl), productInfo = productInfo, category = category, hasDistinctSex = productOption.hasDistinctSex(), @@ -155,6 +177,8 @@ class ProductServiceTest( product = product, storeName = store.name, imageUrls = listOf(productImage.imageUrl), + productDescription = productDescription, + descriptionImageUrls = listOf(productDescriptionImage.imageUrl), productInfo = productInfo, category = category, hasDistinctSex = productOption.hasDistinctSex(), diff --git a/src/test/kotlin/com/petqua/domain/product/ProductCustomRepositoryImplTest.kt b/src/test/kotlin/com/petqua/domain/product/ProductCustomRepositoryImplTest.kt index f9d9180e..c120a107 100644 --- a/src/test/kotlin/com/petqua/domain/product/ProductCustomRepositoryImplTest.kt +++ b/src/test/kotlin/com/petqua/domain/product/ProductCustomRepositoryImplTest.kt @@ -10,11 +10,13 @@ import com.petqua.domain.product.Sorter.REVIEW_COUNT_DESC import com.petqua.domain.product.Sorter.SALE_PRICE_ASC import com.petqua.domain.product.Sorter.SALE_PRICE_DESC import com.petqua.domain.product.category.CategoryRepository -import com.petqua.domain.product.detail.DifficultyLevel.EASY -import com.petqua.domain.product.detail.OptimalTankSize -import com.petqua.domain.product.detail.OptimalTemperature -import com.petqua.domain.product.detail.ProductInfoRepository -import com.petqua.domain.product.detail.Temperament.PEACEFUL +import com.petqua.domain.product.detail.description.ProductDescriptionRepository +import com.petqua.domain.product.detail.info.DifficultyLevel.EASY +import com.petqua.domain.product.detail.info.OptimalTankSize +import com.petqua.domain.product.detail.info.OptimalTemperature +import com.petqua.domain.product.detail.info.ProductInfoRepository +import com.petqua.domain.product.detail.info.Temperament.PEACEFUL +import com.petqua.domain.product.dto.ProductDescriptionResponse import com.petqua.domain.product.dto.ProductReadCondition import com.petqua.domain.product.dto.ProductResponse import com.petqua.domain.product.dto.ProductSearchCondition @@ -28,6 +30,7 @@ import com.petqua.exception.product.ProductExceptionType.NOT_FOUND_PRODUCT import com.petqua.test.DataCleaner import com.petqua.test.fixture.category import com.petqua.test.fixture.product +import com.petqua.test.fixture.productDescription import com.petqua.test.fixture.productInfo import com.petqua.test.fixture.productOption import com.petqua.test.fixture.productRecommendation @@ -51,6 +54,7 @@ class ProductCustomRepositoryImplTest( private val productInfoRepository: ProductInfoRepository, private val categoryRepository: CategoryRepository, private val productOptionRepository: ProductOptionRepository, + private val productDescriptionRepository: ProductDescriptionRepository, private val dataCleaner: DataCleaner, ) : BehaviorSpec({ @@ -63,45 +67,102 @@ class ProductCustomRepositoryImplTest( species = "고정구피" ) ) - val product = productRepository.save( - product( - name = "고정구피", - storeId = store.id, + val productInfo1 = productInfoRepository.save( + productInfo( categoryId = category.id, - discountPrice = ZERO, - reviewCount = 0, - reviewTotalScore = 0 + optimalTemperature = OptimalTemperature(26, 28), + difficultyLevel = EASY, + optimalTankSize = OptimalTankSize.TANK1, + temperament = PEACEFUL, ) ) - val productInfo = productInfoRepository.save( + val productInfo2 = productInfoRepository.save( productInfo( - productId = product.id, - categoryId = 0, + categoryId = category.id, optimalTemperature = OptimalTemperature(26, 28), difficultyLevel = EASY, optimalTankSize = OptimalTankSize.TANK1, temperament = PEACEFUL, ) ) - val productOption = productOptionRepository.save( + val productOption1 = productOptionRepository.save( productOption( - productId = product.id, sex = Sex.MALE, ) ) + val productOption2 = productOptionRepository.save( + productOption( + sex = Sex.MALE, + ) + ) + val productDescription1 = productDescriptionRepository.save( + productDescription( + title = "물생활 핵 인싸어, 레드 브론즈 구피", + content = "레드 턱시도라고도 불리며 지느러미가 아름다운 구피입니다" + ) + ) + val product1 = productRepository.save( + product( + name = "고정구피", + storeId = store.id, + categoryId = category.id, + discountPrice = ZERO, + reviewCount = 0, + reviewTotalScore = 0, + productOptionId = productOption1.id, + productDescriptionId = productDescription1.id, + productInfoId = productInfo1.id, + ) + ) + val product2 = productRepository.save( + product( + name = "팬시구피", + storeId = store.id, + categoryId = category.id, + discountPrice = ZERO, + reviewCount = 0, + reviewTotalScore = 0, + productOptionId = productOption2.id, + productInfoId = productInfo2.id, + ) + ) When("Id를 입력하면") { - val productWithInfoResponse = productRepository.findProductWithInfoByIdOrThrow(product.id) { + val productWithInfoResponse = productRepository.findProductWithInfoByIdOrThrow(product1.id) { ProductException(NOT_FOUND_PRODUCT) } Then("입력한 Id의 상품과 상세정보가 반환된다") { productWithInfoResponse shouldBe ProductWithInfoResponse( - product = product, + product = product1, + storeName = store.name, + productDescription = ProductDescriptionResponse( + title = productDescription1.title.value, + content = productDescription1.content.value + ), + productInfo = productInfo1, + category = category, + productOption = productOption1, + ) + } + } + + When("상세 설명이 없는 상품의 Id를 입력하면") { + val productWithInfoResponse = productRepository.findProductWithInfoByIdOrThrow(product2.id) { + ProductException(NOT_FOUND_PRODUCT) + } + + Then("상세 설명이 없이 입력한 Id의 상품과 상세정보가 반환된다") { + productWithInfoResponse shouldBe ProductWithInfoResponse( + product = product2, storeName = store.name, - productInfo = productInfo, + productDescription = ProductDescriptionResponse( + title = "", + content = "" + ), + productInfo = productInfo2, category = category, - productOption = productOption, + productOption = productOption2, ) } } diff --git a/src/test/kotlin/com/petqua/presentation/product/ProductControllerTest.kt b/src/test/kotlin/com/petqua/presentation/product/ProductControllerTest.kt index a9e0fb97..611e415c 100644 --- a/src/test/kotlin/com/petqua/presentation/product/ProductControllerTest.kt +++ b/src/test/kotlin/com/petqua/presentation/product/ProductControllerTest.kt @@ -15,12 +15,15 @@ import com.petqua.domain.product.Sorter.SALE_PRICE_ASC import com.petqua.domain.product.Sorter.SALE_PRICE_DESC import com.petqua.domain.product.WishProductRepository import com.petqua.domain.product.category.CategoryRepository -import com.petqua.domain.product.detail.DifficultyLevel -import com.petqua.domain.product.detail.OptimalTankSize -import com.petqua.domain.product.detail.OptimalTemperature -import com.petqua.domain.product.detail.ProductImageRepository -import com.petqua.domain.product.detail.ProductInfoRepository -import com.petqua.domain.product.detail.Temperament +import com.petqua.domain.product.detail.description.ProductDescriptionRepository +import com.petqua.domain.product.detail.image.ImageType +import com.petqua.domain.product.detail.image.ImageType.SAMPLE +import com.petqua.domain.product.detail.image.ProductImageRepository +import com.petqua.domain.product.detail.info.DifficultyLevel +import com.petqua.domain.product.detail.info.OptimalTankSize +import com.petqua.domain.product.detail.info.OptimalTemperature +import com.petqua.domain.product.detail.info.ProductInfoRepository +import com.petqua.domain.product.detail.info.Temperament import com.petqua.domain.product.dto.ProductResponse import com.petqua.domain.product.option.ProductOptionRepository import com.petqua.domain.product.option.Sex.HERMAPHRODITE @@ -31,6 +34,7 @@ import com.petqua.exception.product.ProductExceptionType.NOT_FOUND_PRODUCT import com.petqua.test.ApiTestConfig import com.petqua.test.fixture.category import com.petqua.test.fixture.product +import com.petqua.test.fixture.productDescription import com.petqua.test.fixture.productDetailResponse import com.petqua.test.fixture.productImage import com.petqua.test.fixture.productInfo @@ -63,6 +67,7 @@ class ProductControllerTest( private val wishProductRepository: WishProductRepository, private val categoryRepository: CategoryRepository, private val productOptionRepository: ProductOptionRepository, + private val productDescriptionRepository: ProductDescriptionRepository, ) : ApiTestConfig() { init { @@ -78,38 +83,54 @@ class ProductControllerTest( species = "고정구피" ) ) - val product = productRepository.save( - product( - name = "고정구피", - categoryId = category.id, - storeId = store.id, - discountPrice = ZERO, - reviewCount = 0, - reviewTotalScore = 0 + val productDescription = productDescriptionRepository.save( + productDescription( + title = "물생활 핵 인싸어, 레드 브론즈 구피", + content = "레드 턱시도라고도 불리며 지느러미가 아름다운 구피입니다" ) ) val productInfo = productInfoRepository.save( productInfo( - productId = product.id, - categoryId = 0, + categoryId = category.id, optimalTemperature = OptimalTemperature(26, 28), difficultyLevel = DifficultyLevel.EASY, optimalTankSize = OptimalTankSize.TANK1, temperament = Temperament.PEACEFUL, ) ) + val productOption = productOptionRepository.save( + productOption( + sex = HERMAPHRODITE + ) + ) + val product = productRepository.save( + product( + name = "고정구피", + categoryId = category.id, + storeId = store.id, + discountPrice = ZERO, + reviewCount = 0, + reviewTotalScore = 0, + productOptionId = productOption.id, + productDescriptionId = productDescription.id, + productInfoId = productInfo.id + ) + ) val productImage = productImageRepository.save( productImage( productId = product.id, - imageUrl = "image.jpeg" + imageUrl = "image.jpeg", + imageType = SAMPLE ) ) - val productOption = productOptionRepository.save( - productOption( + val productDescriptionImage = productImageRepository.save( + productImage( productId = product.id, - sex = HERMAPHRODITE + imageUrl = "image.jpeg", + imageType = ImageType.DESCRIPTION ) ) + wishProductRepository.save( wishProduct( productId = product.id, @@ -132,6 +153,8 @@ class ProductControllerTest( product = product, storeName = store.name, imageUrls = listOf(productImage.imageUrl), + productDescription = productDescription, + descriptionImageUrls = listOf(productDescriptionImage.imageUrl), productInfo = productInfo, category = category, hasDistinctSex = productOption.hasDistinctSex(), @@ -172,6 +195,8 @@ class ProductControllerTest( product = product, storeName = store.name, imageUrls = listOf(productImage.imageUrl), + productDescription = productDescription, + descriptionImageUrls = listOf(productDescriptionImage.imageUrl), productInfo = productInfo, category = category, hasDistinctSex = productOption.hasDistinctSex(), diff --git a/src/test/kotlin/com/petqua/test/fixture/ProductFixtures.kt b/src/test/kotlin/com/petqua/test/fixture/ProductFixtures.kt index ea4a850c..11e5c389 100644 --- a/src/test/kotlin/com/petqua/test/fixture/ProductFixtures.kt +++ b/src/test/kotlin/com/petqua/test/fixture/ProductFixtures.kt @@ -5,12 +5,16 @@ import com.petqua.domain.keyword.ProductKeyword import com.petqua.domain.product.Product import com.petqua.domain.product.WishCount import com.petqua.domain.product.category.Category -import com.petqua.domain.product.detail.DifficultyLevel -import com.petqua.domain.product.detail.OptimalTankSize -import com.petqua.domain.product.detail.OptimalTemperature -import com.petqua.domain.product.detail.ProductImage -import com.petqua.domain.product.detail.ProductInfo -import com.petqua.domain.product.detail.Temperament +import com.petqua.domain.product.detail.description.ProductDescription +import com.petqua.domain.product.detail.description.ProductDescriptionContent +import com.petqua.domain.product.detail.description.ProductDescriptionTitle +import com.petqua.domain.product.detail.image.ImageType +import com.petqua.domain.product.detail.image.ProductImage +import com.petqua.domain.product.detail.info.DifficultyLevel +import com.petqua.domain.product.detail.info.OptimalTankSize +import com.petqua.domain.product.detail.info.OptimalTemperature +import com.petqua.domain.product.detail.info.ProductInfo +import com.petqua.domain.product.detail.info.Temperament import com.petqua.domain.product.dto.ProductResponse import com.petqua.domain.product.option.ProductOption import com.petqua.domain.product.option.Sex @@ -30,29 +34,33 @@ fun product( reviewCount: Int = 0, reviewTotalScore: Int = 0, thumbnailUrl: String = "image.jpg", - description: String = "description", isDeleted: Boolean = false, canDeliverySafely: Boolean = true, canDeliveryCommonly: Boolean = true, canPickUp: Boolean = true, + productOptionId: Long = 0, + productDescriptionId: Long? = null, + productInfoId: Long = 0, ): Product { return Product( - id, - name, - categoryId, - price.setScale(DEFAULT_SCALE), - storeId, - discountRate, - discountPrice.setScale(DEFAULT_SCALE), - WishCount(wishCount), - reviewCount, - reviewTotalScore, - thumbnailUrl, - description, - isDeleted, - canDeliverySafely, - canDeliveryCommonly, - canPickUp, + id = id, + name = name, + categoryId = categoryId, + price = price.setScale(DEFAULT_SCALE), + storeId = storeId, + discountRate = discountRate, + discountPrice = discountPrice.setScale(DEFAULT_SCALE), + wishCount = WishCount(wishCount), + reviewCount = reviewCount, + reviewTotalScore = reviewTotalScore, + thumbnailUrl = thumbnailUrl, + isDeleted = isDeleted, + canDeliverSafely = canDeliverySafely, + canDeliverCommonly = canDeliveryCommonly, + canPickUp = canPickUp, + productOptionId = productOptionId, + productDescriptionId = productDescriptionId, + productInfoId = productInfoId ) } @@ -70,7 +78,6 @@ fun productKeyword( fun productInfo( id: Long = 0L, - productId: Long, categoryId: Long, optimalTemperature: OptimalTemperature, difficultyLevel: DifficultyLevel, @@ -79,7 +86,6 @@ fun productInfo( ): ProductInfo { return ProductInfo( id = id, - productId = productId, categoryId = categoryId, optimalTemperature = optimalTemperature, difficultyLevel = difficultyLevel, @@ -92,32 +98,46 @@ fun productImage( id: Long = 0, productId: Long, imageUrl: String, + imageType: ImageType, ): ProductImage { return ProductImage( id = id, productId = productId, imageUrl = imageUrl, + imageType = imageType, ) } fun productOption( id: Long = 0, - productId: Long, sex: Sex, additionalPrice: BigDecimal = BigDecimal.ZERO, ): ProductOption { return ProductOption( id = id, - productId = productId, sex = sex, additionalPrice = additionalPrice, ) } +fun productDescription( + id: Long = 0, + title: String = "제목", + content: String = "내용", +): ProductDescription { + return ProductDescription( + id = id, + title = ProductDescriptionTitle(title), + content = ProductDescriptionContent(content) + ) +} + fun productDetailResponse( product: Product, storeName: String, imageUrls: List, + productDescription: ProductDescription, + descriptionImageUrls: List, productInfo: ProductInfo, category: Category, hasDistinctSex: Boolean, @@ -135,9 +155,10 @@ fun productDetailResponse( wishCount = product.wishCount.value, reviewCount = product.reviewCount, reviewAverageScore = product.averageReviewScore(), - thumbnailUrl = product.thumbnailUrl, imageUrls = imageUrls, - description = product.description, + descriptionTitle = productDescription.title.value, + descriptionContent = productDescription.content.value, + descriptionImageUrls = descriptionImageUrls, canDeliverSafely = product.canDeliverSafely, canDeliverCommonly = product.canDeliverCommonly, canPickUp = product.canPickUp,