feat(gift): 선물 카테고리 운영 필드를 추가한다

This commit is contained in:
2026-09-30 17:37:23 +09:00
parent dda5de4d61
commit 13a842a9a5
4 changed files with 98 additions and 4 deletions
@@ -4,14 +4,20 @@ import kr.co.vividnext.sodalive.v2.gift.application.GiftCategoryCommand
import kr.co.vividnext.sodalive.v2.gift.application.GiftSizePriceCommand
data class AdminGiftCategoryRequest(
val classificationNumber: String,
val categoryCode: String,
val name: String,
val receiptCode: String,
val representativeItem: String,
val requiresDamageWaiver: Boolean,
val isActive: Boolean
) {
fun toCommand() = GiftCategoryCommand(
classificationNumber = classificationNumber,
categoryCode = categoryCode,
name = name,
receiptCode = receiptCode,
representativeItem = representativeItem,
requiresDamageWaiver = requiresDamageWaiver,
isActive = isActive
)
@@ -9,15 +9,28 @@ import javax.persistence.UniqueConstraint
@Entity
@Table(
name = "gift_category",
uniqueConstraints = [UniqueConstraint(name = "uk_gift_category_code", columnNames = ["category_code"])]
uniqueConstraints = [
UniqueConstraint(name = "uk_gift_category_classification_number", columnNames = ["classification_number"]),
UniqueConstraint(name = "uk_gift_category_code", columnNames = ["category_code"]),
UniqueConstraint(name = "uk_gift_category_receipt_code", columnNames = ["receipt_code"])
]
)
class GiftCategory(
@Column(name = "classification_number", nullable = false, length = 3)
var classificationNumber: String,
@Column(name = "category_code", nullable = false, length = 50)
val categoryCode: String,
@Column(name = "name", nullable = false, length = 50)
var name: String,
@Column(name = "receipt_code", nullable = false, length = 9)
var receiptCode: String,
@Column(name = "representative_item", nullable = false, length = 100)
var representativeItem: String,
@Column(name = "requires_damage_waiver", nullable = false)
var requiresDamageWaiver: Boolean = false,
@@ -15,16 +15,22 @@ import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime
data class GiftCategoryCommand(
val classificationNumber: String,
val categoryCode: String,
val name: String,
val receiptCode: String,
val representativeItem: String,
val requiresDamageWaiver: Boolean,
val isActive: Boolean
)
data class GiftCategoryResult(
val categoryId: Long,
val classificationNumber: String,
val categoryCode: String,
val name: String,
val receiptCode: String,
val representativeItem: String,
val requiresDamageWaiver: Boolean,
val isActive: Boolean
)
@@ -66,8 +72,11 @@ class GiftAdminService(
validateCategory(command)
return categoryRepository.save(
GiftCategory(
classificationNumber = command.classificationNumber,
categoryCode = command.categoryCode,
name = command.name,
receiptCode = command.receiptCode,
representativeItem = command.representativeItem,
requiresDamageWaiver = command.requiresDamageWaiver,
isActive = command.isActive
)
@@ -78,7 +87,10 @@ class GiftAdminService(
fun updateCategory(categoryId: Long, command: GiftCategoryCommand): GiftCategoryResult {
validateCategory(command)
val category = categoryRepository.findByIdOrNull(categoryId) ?: throw invalidRequest()
category.classificationNumber = command.classificationNumber
category.name = command.name
category.receiptCode = command.receiptCode
category.representativeItem = command.representativeItem
category.requiresDamageWaiver = command.requiresDamageWaiver
category.isActive = command.isActive
return category.toResult()
@@ -172,7 +184,11 @@ class GiftAdminService(
command.categoryCode.isBlank() ||
command.categoryCode.length > 50 ||
command.name.isBlank() ||
command.name.length > 50
command.name.length > 50 ||
!CLASSIFICATION_NUMBER_REGEX.matches(command.classificationNumber) ||
!RECEIPT_CODE_REGEX.matches(command.receiptCode) ||
command.representativeItem.isBlank() ||
command.representativeItem.length > 100
) {
throw invalidRequest()
}
@@ -184,8 +200,11 @@ class GiftAdminService(
private fun GiftCategory.toResult() = GiftCategoryResult(
categoryId = id ?: throw invalidRequest(),
classificationNumber = classificationNumber,
categoryCode = categoryCode,
name = name,
receiptCode = receiptCode,
representativeItem = representativeItem,
requiresDamageWaiver = requiresDamageWaiver,
isActive = isActive
)
@@ -206,5 +225,7 @@ class GiftAdminService(
GiftStatus.ARRIVED_AT_MAILBOX,
GiftStatus.INSPECTION_COMPLETED
)
val CLASSIFICATION_NUMBER_REGEX = Regex("\\d{3}")
val RECEIPT_CODE_REGEX = Regex("[A-Z]{1,9}")
}
}
@@ -48,20 +48,58 @@ class GiftAdminServiceTest @Autowired constructor(
@DisplayName("카테고리를 등록, 수정, 논리삭제한다")
fun shouldCreateUpdateAndDeactivateCategory() {
val created = service.createCategory(
GiftCategoryCommand(categoryCode = "DOLL", name = "인형", requiresDamageWaiver = true, isActive = true)
GiftCategoryCommand(
classificationNumber = "100",
categoryCode = "DOLL",
name = "인형",
receiptCode = "A",
representativeItem = "피규어",
requiresDamageWaiver = true,
isActive = true
)
)
val updated = service.updateCategory(
created.categoryId,
GiftCategoryCommand(categoryCode = "DOLL", name = "큰 인형", requiresDamageWaiver = false, isActive = true)
GiftCategoryCommand(
classificationNumber = "101",
categoryCode = "DOLL",
name = "큰 인형",
receiptCode = "B",
representativeItem = "대형 피규어",
requiresDamageWaiver = false,
isActive = true
)
)
service.deleteCategory(created.categoryId)
val saved = categoryRepository.findById(created.categoryId).orElseThrow()
assertEquals("101", updated.classificationNumber)
assertEquals("DOLL", updated.categoryCode)
assertEquals("큰 인형", updated.name)
assertEquals("B", updated.receiptCode)
assertEquals("대형 피규어", updated.representativeItem)
assertFalse(updated.requiresDamageWaiver)
assertFalse(saved.isActive)
}
@Test
@DisplayName("카테고리 분류번호와 접수코드 형식을 검증한다")
fun shouldValidateCategoryClassificationNumberAndReceiptCode() {
val invalidClassificationNumber = assertThrows(SodaException::class.java) {
service.createCategory(categoryCommand(classificationNumber = "10A"))
}
val invalidReceiptCode = assertThrows(SodaException::class.java) {
service.createCategory(categoryCommand(receiptCode = "A1"))
}
val blankRepresentativeItem = assertThrows(SodaException::class.java) {
service.createCategory(categoryCommand(representativeItem = " "))
}
assertEquals("common.error.invalid_request", invalidClassificationNumber.messageKey)
assertEquals("common.error.invalid_request", invalidReceiptCode.messageKey)
assertEquals("common.error.invalid_request", blankRepresentativeItem.messageKey)
}
@Test
@DisplayName("사이즈 가격을 수정하고 salePriceCan이 basePriceCan보다 크면 거부한다")
fun shouldUpdateSizePriceAndRejectInvalidSalePrice() {
@@ -213,6 +251,22 @@ class GiftAdminServiceTest @Autowired constructor(
return gift to delivery
}
private fun categoryCommand(
classificationNumber: String = "100",
categoryCode: String = "DOLL",
name: String = "인형",
receiptCode: String = "A",
representativeItem: String = "피규어"
) = GiftCategoryCommand(
classificationNumber = classificationNumber,
categoryCode = categoryCode,
name = name,
receiptCode = receiptCode,
representativeItem = representativeItem,
requiresDamageWaiver = true,
isActive = true
)
private companion object {
const val APPLICATION_NO = "G20260929000001"
const val SENDER_MEMBER_ID = 1L