fix(gift): 관리자 취소 시각을 초 단위로 정규화한다

This commit is contained in:
2026-10-22 19:27:45 +09:00
parent 97c7de6f6e
commit 82ce6f8830
2 changed files with 25 additions and 3 deletions
@@ -16,6 +16,7 @@ import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional import org.springframework.transaction.annotation.Transactional
import java.time.LocalDateTime import java.time.LocalDateTime
import java.time.temporal.ChronoUnit
data class GiftCategoryCommand( data class GiftCategoryCommand(
val classificationNumber: String, val classificationNumber: String,
@@ -157,12 +158,13 @@ class GiftAdminService(
val gift = giftRepository.findByApplicationNoForUpdate(applicationNo) ?: throw invalidRequest() val gift = giftRepository.findByApplicationNoForUpdate(applicationNo) ?: throw invalidRequest()
if (gift.status != GiftStatus.RECEIVED) throw invalidRequest() if (gift.status != GiftStatus.RECEIVED) throw invalidRequest()
val delivery = giftDeliveryRepository.findByGiftId(requireNotNull(gift.id)) ?: throw invalidRequest() val delivery = giftDeliveryRepository.findByGiftId(requireNotNull(gift.id)) ?: throw invalidRequest()
val canceledAt = now.truncatedTo(ChronoUnit.SECONDS)
gift.status = GiftStatus.CANCELED gift.status = GiftStatus.CANCELED
delivery.canceledAt = now delivery.canceledAt = canceledAt
canPaymentService.refundGiftCan(gift.senderMemberId, gift.canUsageId) canPaymentService.refundGiftCan(gift.senderMemberId, gift.canUsageId)
return GiftOperationStatusResult(gift.applicationNo, gift.status, gift.status.displayName, now) return GiftOperationStatusResult(gift.applicationNo, gift.status, gift.status.displayName, canceledAt)
} }
@Transactional @Transactional
@@ -25,6 +25,7 @@ import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest
import org.springframework.context.annotation.Import import org.springframework.context.annotation.Import
import java.time.LocalDateTime import java.time.LocalDateTime
import javax.persistence.EntityManager
@DataJpaTest( @DataJpaTest(
properties = [ properties = [
@@ -39,7 +40,8 @@ class GiftAdminServiceTest @Autowired constructor(
private val sizePriceRepository: GiftSizePriceRepository, private val sizePriceRepository: GiftSizePriceRepository,
private val giftRepository: GiftRepository, private val giftRepository: GiftRepository,
private val giftDeliveryRepository: GiftDeliveryRepository, private val giftDeliveryRepository: GiftDeliveryRepository,
private val giftMailboxRepository: GiftMailboxRepository private val giftMailboxRepository: GiftMailboxRepository,
private val entityManager: EntityManager
) { ) {
private val giftPushService = Mockito.mock(GiftPushService::class.java) private val giftPushService = Mockito.mock(GiftPushService::class.java)
private val canPaymentService = Mockito.mock(CanPaymentService::class.java) private val canPaymentService = Mockito.mock(CanPaymentService::class.java)
@@ -332,6 +334,24 @@ class GiftAdminServiceTest @Autowired constructor(
Mockito.verifyNoInteractions(giftPushService) Mockito.verifyNoInteractions(giftPushService)
} }
@ParameterizedTest
@ValueSource(ints = [0, 123456789, 999999999])
@DisplayName("관리자 취소 시각은 나노초 입력에도 초 단위 저장값과 응답이 일치한다")
fun shouldPersistAndReturnSameSecondPrecisionCancellationTime(nanos: Int) {
val (gift, _) = saveGift(GiftStatus.RECEIVED)
val giftId = requireNotNull(gift.id)
val now = LocalDateTime.of(2026, 10, 22, 23, 59, 59, nanos)
val result = service.cancelGift(APPLICATION_NO, now)
entityManager.flush()
entityManager.clear()
val persisted = requireNotNull(giftDeliveryRepository.findByGiftId(giftId)?.canceledAt)
assertEquals(persisted, result.occurredAt)
assertEquals(LocalDateTime.of(2026, 10, 22, 23, 59, 59), persisted)
assertEquals(GiftStatus.CANCELED, giftRepository.findById(giftId).orElseThrow().status)
}
@ParameterizedTest @ParameterizedTest
@EnumSource(value = GiftStatus::class, names = ["RECEIVED"], mode = EnumSource.Mode.EXCLUDE) @EnumSource(value = GiftStatus::class, names = ["RECEIVED"], mode = EnumSource.Mode.EXCLUDE)
@DisplayName("운영자는 접수가 아닌 모든 상태의 선물을 취소할 수 없다") @DisplayName("운영자는 접수가 아닌 모든 상태의 선물을 취소할 수 없다")