feat(gift): 카테고리별 신청번호를 발급한다

This commit is contained in:
2026-09-30 17:38:24 +09:00
parent f3f46c413c
commit 2bda30e7e2
4 changed files with 81 additions and 17 deletions
@@ -454,7 +454,15 @@ class GiftCommandServiceTest {
val giftPushService = Mockito.mock(GiftPushService::class.java)
val sender = Member(password = "password", nickname = "sender", container = "aos").apply { id = SENDER_ID }
val creator = Member(password = "password", nickname = "creator").apply { id = RECIPIENT_ID }
val category = GiftCategory("DOLL", "인형", false, true).apply { id = CATEGORY_ID }
val category = GiftCategory(
classificationNumber = "100",
categoryCode = "DOLL",
name = "인형",
receiptCode = "A",
representativeItem = "피규어",
requiresDamageWaiver = false,
isActive = true
).apply { id = CATEGORY_ID }
val sizePrice = GiftSizePrice(GiftSize.SMALL, BASE_PRICE_CAN, SALE_PRICE_CAN, true)
lateinit var savedGift: Gift
lateinit var savedDelivery: GiftDelivery
@@ -486,7 +494,7 @@ class GiftCommandServiceTest {
setCreatorExists(true)
Mockito.`when`(categoryRepository.findById(CATEGORY_ID)).thenReturn(Optional.of(category))
Mockito.`when`(sizePriceRepository.findBySizeCode(GiftSize.SMALL)).thenReturn(sizePrice)
Mockito.`when`(applicationNoGenerator.generate(NOW)).thenReturn(APPLICATION_NO)
Mockito.`when`(applicationNoGenerator.generate(category, NOW)).thenReturn(APPLICATION_NO)
Mockito.`when`(canPaymentService.spendGiftCan(SENDER_ID, SALE_PRICE_CAN, "aos")).thenReturn(USE_CAN_ID)
Mockito.`when`(giftRepository.save(Mockito.any(Gift::class.java))).thenAnswer { invocation ->
invocation.getArgument<Gift>(0).apply {
@@ -1,7 +1,10 @@
package kr.co.vividnext.sodalive.v2.gift.application
import kr.co.vividnext.sodalive.configs.QueryDslConfig
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftApplicationNoSequence
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftApplicationNoSequenceRepository
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftCategory
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftCategoryRepository
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.DisplayName
@@ -24,24 +27,56 @@ import java.util.concurrent.Executors
@DisplayName("선물 신청번호 채번 테스트")
class GiftApplicationNoGeneratorTest @Autowired constructor(
private val repository: GiftApplicationNoSequenceRepository,
private val categoryRepository: GiftCategoryRepository,
private val transactionManager: PlatformTransactionManager
) {
@BeforeEach
fun setUp() {
repository.deleteAll()
categoryRepository.deleteAll()
}
@Test
@DisplayName("같은 날짜 신청번호를 순서대로 발급한다")
fun shouldGenerateSequentialApplicationNoByDate() {
@DisplayName("같은 카테고리와 날짜 신청번호를 순서대로 발급한다")
fun shouldGenerateSequentialApplicationNoByCategoryAndDate() {
val generator = GiftApplicationNoGenerator(repository, transactionManager)
val now = LocalDateTime.of(2026, 9, 29, 12, 0)
val category = saveCategory("100", "DOLL", "A")
val first = generator.generate(now)
val second = generator.generate(now)
val first = generator.generate(category, now)
val second = generator.generate(category, now)
assertEquals("G20260929000001", first)
assertEquals("G20260929000002", second)
assertEquals("A-1002609290001", first)
assertEquals("A-1002609290002", second)
}
@Test
@DisplayName("카테고리와 날짜가 다르면 sequence를 따로 발급한다")
fun shouldGenerateApplicationNoByCategoryAndDateIndependently() {
val generator = GiftApplicationNoGenerator(repository, transactionManager)
val doll = saveCategory("100", "DOLL", "A")
val food = saveCategory("200", "FOOD", "C")
val dollFirst = generator.generate(doll, LocalDateTime.of(2026, 9, 29, 12, 0))
val foodFirst = generator.generate(food, LocalDateTime.of(2026, 9, 29, 12, 0))
val dollNextDay = generator.generate(doll, LocalDateTime.of(2026, 9, 30, 12, 0))
assertEquals("A-1002609290001", dollFirst)
assertEquals("C-2002609290001", foodFirst)
assertEquals("A-1002609300001", dollNextDay)
}
@Test
@DisplayName("sequence가 9999를 초과하면 자리수를 늘린다")
fun shouldExpandSequenceDigitsAfter9999() {
val generator = GiftApplicationNoGenerator(repository, transactionManager)
val category = saveCategory("100", "DOLL", "A")
val now = LocalDateTime.of(2026, 9, 30, 12, 0)
repository.save(GiftApplicationNoSequence(categoryId = category.id!!, sequenceDate = "260930", lastSequence = 9999))
val applicationNo = generator.generate(category, now)
assertEquals("A-10026093010000", applicationNo)
}
@Test
@@ -49,12 +84,13 @@ class GiftApplicationNoGeneratorTest @Autowired constructor(
fun shouldGenerateUniqueApplicationNoConcurrently() {
val generator = GiftApplicationNoGenerator(repository, transactionManager)
val now = LocalDateTime.of(2026, 9, 29, 12, 0)
val category = saveCategory("100", "DOLL", "A")
val executor = Executors.newFixedThreadPool(4)
val applicationNos = try {
executor.invokeAll(
(1..10).map {
Callable { generator.generate(now) }
Callable { generator.generate(category, now) }
}
).map { it.get() }
} finally {
@@ -62,7 +98,18 @@ class GiftApplicationNoGeneratorTest @Autowired constructor(
}
assertEquals(10, applicationNos.toSet().size)
assertEquals("G20260929000001", applicationNos.minOrNull())
assertEquals("G20260929000010", applicationNos.maxOrNull())
assertEquals("A-1002609290001", applicationNos.minOrNull())
assertEquals("A-1002609290010", applicationNos.maxOrNull())
}
private fun saveCategory(classificationNumber: String, categoryCode: String, receiptCode: String) =
categoryRepository.save(
GiftCategory(
classificationNumber = classificationNumber,
categoryCode = categoryCode,
name = "인형",
receiptCode = receiptCode,
representativeItem = "피규어"
)
)
}