diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/api/admin/gift/dto/AdminGiftRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/api/admin/gift/dto/AdminGiftRequest.kt index 0c1121a9..a53b906f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/api/admin/gift/dto/AdminGiftRequest.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/api/admin/gift/dto/AdminGiftRequest.kt @@ -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 ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/adapter/out/persistence/GiftCategory.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/adapter/out/persistence/GiftCategory.kt index 8974588f..807b17ec 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/adapter/out/persistence/GiftCategory.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/adapter/out/persistence/GiftCategory.kt @@ -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, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/application/GiftAdminService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/application/GiftAdminService.kt index c61bcc2d..9ba9ae97 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/application/GiftAdminService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/application/GiftAdminService.kt @@ -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}") } } diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/gift/application/GiftAdminServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/gift/application/GiftAdminServiceTest.kt index 4b3be603..88c14e74 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/gift/application/GiftAdminServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/gift/application/GiftAdminServiceTest.kt @@ -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