Skip to content

Commit

Permalink
feat: Product 도메인 엔티티 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
Ogu1208 committed Aug 3, 2024
1 parent 4a42e3b commit e83f083
Show file tree
Hide file tree
Showing 13 changed files with 331 additions and 0 deletions.
50 changes: 50 additions & 0 deletions src/main/kotlin/org/store/clothstar/product/domain/entity/Item.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.store.clothstar.product.domain.entity

import jakarta.persistence.*
import org.store.clothstar.product.domain.type.DisplayStatus
import org.store.clothstar.product.domain.type.SaleStatus

/**
* {
* "id": 1,
* "name": "중청/롱/S",
* "price": 29900,
* "finalPrice": 19900,
* "itemCode": null,
* "deliveryType": "GENERAL",
* "remainStock": 4,
* "productLine": 1,
* "displayStatus": "VISIBLE", // 또는 "HIDDEN" 등 해당되는 값을 사용
* "itemAttributes": [
* { "optionId": 1, "name": "색상", "value": "중청", "valueId": 1 },
* { "optionId": 2, "name": "기장", "value": "롱", "valueId": 6 },
* { "optionId": 3, "name": "사이즈", "value": "S", "valueId": 8 }
* ]
* }
*/
@Entity
class Item (
@Column
var name: String,
@Column
var price: Int,
@Column
var stock: Int,
@Column
var saleStatus: SaleStatus,
@Column
var displayStatus: DisplayStatus,

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_line_id")
val product: Product

) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L

@ElementCollection
@CollectionTable(name = "item_attributes", joinColumns = [JoinColumn(name = "item_id")])

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.store.clothstar.product.domain.entity

import jakarta.persistence.Embeddable

/**
* { "optionId": 1, "name": "색상", "value": "중청", "valueId": 1 }
*/
@Embeddable
data class ItemAttribute (
var optionId: Long,
var name: String,
var value: String,
var valueId: Long
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package org.store.clothstar.product.domain.entity

import jakarta.persistence.*
import org.store.clothstar.product.domain.type.ProductColor


/***
* {
* "id": 1,
* "code": "#5C88C9",
* "value": "중청",
* "productOption": 1
* }
*/
@Entity
class OptionValue (
val productColor: ProductColor, // 색상 코드
@Column(nullable = false)
var value: String,

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_option_id")
val productOption: ProductOption
) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0
}
118 changes: 118 additions & 0 deletions src/main/kotlin/org/store/clothstar/product/domain/entity/Product.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package org.store.clothstar.product.domain.entity

import jakarta.persistence.*
import org.store.clothstar.common.entity.BaseEntity
import org.store.clothstar.member.domain.Member
import org.store.clothstar.product.domain.type.DisplayStatus
import org.store.clothstar.product.domain.type.ProductColor
import org.store.clothstar.product.domain.type.SaleStatus
import org.store.clothstar.product.dto.request.UpdateProductRequest

@Entity
class Product (
// 연관 관계 필드 (N:1)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
val member: Member,

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_id")
val category: Category,

// 기본 정보 필드
var name: String,
var content: String,
var price: Int,
@ElementCollection
@CollectionTable(name = "product_color", joinColumns = [JoinColumn(name = "product_id")])
var productColors: MutableList<ProductColor>? = mutableListOf(),

// 이미지 목록
@ElementCollection
@CollectionTable(name = "product_image", joinColumns = [JoinColumn(name = "product_line_id")])
var imageList: MutableList<ProductImage> = mutableListOf(),

// 기타 정보
var saleCount: Long,
@Enumerated(EnumType.STRING)
var displayStatus: DisplayStatus, // 진열 여부
@Enumerated(EnumType.STRING)
var saleStatus: SaleStatus, // 판매 상태

// 연관 관계 (1:N)
@OneToMany(mappedBy = "product_line_id", cascade = [CascadeType.ALL], fetch = FetchType.LAZY)
var productOptions: MutableSet<ProductOption> = mutableSetOf(),

@OneToMany(fetch = FetchType.LAZY, cascade = [CascadeType.ALL])
var items: MutableList<Item> = mutableListOf()
): BaseEntity() {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
var id:Long = 0

/**
* @param UpdateProductRequest
* @return null
*/
fun update(request: UpdateProductRequest) {
this.name = request.name ?: this.name
this.content = request.content ?: this.content
this.price = request.price ?: this.price
this.displayStatus = request.displayStatus
this.saleStatus = request.saleStatus ?: this.saleStatus

// imageList 업데이트 (이미지 리스트가 완전히 교체되는 경우)
request.imageList?.let {
this.imageList.clear()
this.imageList.addAll(it)
}

// productOptions 업데이트 로직 (삭제 불가)
request.productOptions?.let {
val newOptions = it.toSet()
val existingOptions = this.productOptions.map { it.id }.toSet()

// 기존 옵션들에 포함되지 않은 새 옵션 추가
newOptions.forEach { newOption ->
if (newOption.id !in existingOptions) {
this.productOptions.add(newOption)
}
}

// 기존 옵션 삭제 방지
val toRemove = this.productOptions.filterNot { it.id in newOptions.map { it.id } }
if (toRemove.isNotEmpty()) {
throw IllegalArgumentException("Existing product options cannot be removed")
}
}

// items 업데이트 로직 (삭제 불가)
request.items?.let {
val newItems = it.toSet()
val existingItems = this.items.map { it.id }.toSet()

// 기존 아이템들에 포함되지 않은 새 아이템 추가
newItems.forEach { newItem ->
if (newItem.id !in existingItems) {
this.items.add(newItem)
}
}

// 기존 아이템 삭제 방지
val toRemove = this.items.filterNot { it.id in newItems.map { it.id } }
if (toRemove.isNotEmpty()) {
throw IllegalArgumentException("Existing items cannot be removed")
}
}

// productColors 업데이트 로직
request.productColors?.let {
this.productColors?.clear()
this.productColors?.addAll(it)
}
}

fun updateSaleStatus(saleStatus: SaleStatus) {
this.saleStatus = saleStatus
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.store.clothstar.product.domain.entity

import jakarta.persistence.Embeddable
import jakarta.persistence.EnumType
import jakarta.persistence.Enumerated
import org.store.clothstar.product.domain.type.ImageType

@Embeddable
class ProductImage (
val imageUrl: String,
@Enumerated(EnumType.STRING)
val imageType: ImageType
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.store.clothstar.product.domain.entity

import jakarta.persistence.*
import org.store.clothstar.product.domain.type.OptionType


/**
* {
* "id": 1,
* "name": "색상",
* "order": 0,
* "required": true,
* "optionType": "BASIC",
* "catalogProduct": 1,
* "optionValues": [
* { "id": 1, "code": "#5C88C9", "value": "중청" },
* { "id": 2, "code": "#778899", "value": "애쉬블루" },
* { "id": 3, "code": null, "value": "연청" },
* { "id": 4, "code": null, "value": "(썸머)연청" },
* { "id": 5, "code": null, "value": "(썸머)중청" }
* ]
* }
*/
@Entity
class ProductOption (
val name: String,
val order: Int = 0,
val required: Boolean = true,
@Enumerated(EnumType.STRING)
val optionType: OptionType,

) {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
val id: Long = 0L

@OneToMany(mappedBy = "product_line_id", cascade = [CascadeType.ALL], orphanRemoval = true)
var optionValues: MutableList<OptionValue> = mutableListOf()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.store.clothstar.product.domain.type

enum class DeliveryType {
GENERAL, // 일반 배송
SHACK // 빠른 배송
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.store.clothstar.product.domain.type

enum class DisplayStatus {
VISIBLE,
HIDDEN
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package org.store.clothstar.product.domain.type

enum class ImageType {
MAIN,// 대표 이미지
SUB // 추가 이미지
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.store.clothstar.product.domain.type

enum class OptionType {
BASIC
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.store.clothstar.product.domain.type

enum class ProductColor {
WHITE,
BLACK,
GRAY,
BLUE,
BROWN,
PINK,
GREEN,
BEIGE,
NAVY,
KHAKI,
DENIM,
ETC
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.store.clothstar.product.domain.type

enum class SaleStatus {
ALL,
ON_SALE,
SALE_ENDED,
SOLD_OUT
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.store.clothstar.product.dto.request

import org.store.clothstar.product.domain.entity.Item
import org.store.clothstar.product.domain.entity.ProductImage
import org.store.clothstar.product.domain.entity.ProductOption
import org.store.clothstar.product.domain.type.DisplayStatus
import org.store.clothstar.product.domain.type.ProductColor
import org.store.clothstar.product.domain.type.SaleStatus

class UpdateProductRequest (
val name: String?,
val content: String?,
val price: Int?,
val productColors: List<ProductColor>?,
val displayStatus: DisplayStatus
val saleStatus: SaleStatus?,
val imageList: List<ProductImage>?,
val productOptions: Set<ProductOption>?,
val items: List<Item>?
) {

}

0 comments on commit e83f083

Please sign in to comment.