diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/adapter/out/persistence/GiftDelivery.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/adapter/out/persistence/GiftDelivery.kt index 747e4a6b..748e1757 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/adapter/out/persistence/GiftDelivery.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/gift/adapter/out/persistence/GiftDelivery.kt @@ -84,4 +84,11 @@ class GiftDelivery( @Column(name = "undeliverable_reason", length = 255) var undeliverableReason: String? = null -) : BaseEntity() +) : BaseEntity() { + fun hasCompleteRecipientInformation() = listOf( + recipientName, + recipientPhoneNumber, + recipientZipCode, + recipientAddress + ).none { it.isNullOrBlank() } +} 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 a3569f59..a4ba308d 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 @@ -203,6 +203,7 @@ class GiftAdminService( val gift = giftRepository.findByApplicationNo(applicationNo) ?: throw invalidRequest() if (gift.status != GiftStatus.INSPECTION_COMPLETED) throw invalidRequest() val delivery = giftDeliveryRepository.findByGiftId(requireNotNull(gift.id)) ?: throw invalidRequest() + if (!delivery.hasCompleteRecipientInformation()) throw invalidRequest() gift.status = GiftStatus.DELIVERED delivery.deliveredAt = now diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/admin/gift/adapter/in/web/AdminGiftControllerTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/admin/gift/adapter/in/web/AdminGiftControllerTest.kt index da1787e5..98064c95 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/admin/gift/adapter/in/web/AdminGiftControllerTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/admin/gift/adapter/in/web/AdminGiftControllerTest.kt @@ -332,7 +332,7 @@ class AdminGiftControllerTest @Autowired constructor( @Test @DisplayName("관리자는 검수완료 선물을 전달완료 처리한다") fun shouldCompleteGiftDelivery() { - saveGift(GiftStatus.INSPECTION_COMPLETED) + saveGift(GiftStatus.INSPECTION_COMPLETED, withRecipientAddress = true) mockMvc.perform(post("/api/v2/admin/gifts/$APPLICATION_NO/complete-delivery").with(user("admin").roles("ADMIN"))) .andExpect(status().isOk) @@ -342,7 +342,17 @@ class AdminGiftControllerTest @Autowired constructor( .andExpect(jsonPath("$.data.occurredAt").value(endsWith("Z"))) } - private fun saveGift(status: GiftStatus) { + @Test + @DisplayName("관리자는 수취인 정보가 없는 검수완료 선물을 전달완료 처리할 수 없다") + fun shouldRejectGiftDeliveryWithoutRecipientAddress() { + saveGift(GiftStatus.INSPECTION_COMPLETED) + + mockMvc.perform(post("/api/v2/admin/gifts/$APPLICATION_NO/complete-delivery").with(user("admin").roles("ADMIN"))) + .andExpect(status().isOk) + .andExpect(jsonPath("$.success").value(false)) + } + + private fun saveGift(status: GiftStatus, withRecipientAddress: Boolean = false) { val gift = giftRepository.save( Gift( applicationNo = APPLICATION_NO, @@ -368,6 +378,10 @@ class AdminGiftControllerTest @Autowired constructor( senderPhoneNumber = "01012345678", senderZipCode = "06234", senderAddress = "서울시 강남구", + recipientName = "김소다".takeIf { withRecipientAddress }, + recipientPhoneNumber = "01098765432".takeIf { withRecipientAddress }, + recipientZipCode = "04524".takeIf { withRecipientAddress }, + recipientAddress = "서울시 중구".takeIf { withRecipientAddress }, trackingDeadlineAt = NOW.minusDays(1), trackingRegisteredAt = NOW.minusHours(1) ) 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 b003dda6..86610855 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 @@ -16,6 +16,8 @@ import org.junit.jupiter.api.Assertions.assertFalse import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource import org.mockito.Mockito import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest @@ -248,6 +250,7 @@ class GiftAdminServiceTest @Autowired constructor( @DisplayName("운영자는 검수 완료 선물을 전달 완료 처리한다") fun shouldCompleteDeliveryForInspectionCompletedGift() { val (gift, delivery) = saveGift(GiftStatus.INSPECTION_COMPLETED) + populateRecipientInformation(delivery) val result = service.completeDelivery(APPLICATION_NO, NOW) @@ -262,7 +265,8 @@ class GiftAdminServiceTest @Autowired constructor( @Test @DisplayName("검수 완료 상태가 아니면 운영 전달 완료 처리할 수 없다") fun shouldRejectDeliveryCompletionWhenGiftIsNotInspectionCompleted() { - saveGift(GiftStatus.ARRIVED_AT_MAILBOX) + val (_, delivery) = saveGift(GiftStatus.ARRIVED_AT_MAILBOX) + populateRecipientInformation(delivery) val exception = assertThrows(SodaException::class.java) { service.completeDelivery(APPLICATION_NO, NOW) @@ -271,6 +275,50 @@ class GiftAdminServiceTest @Autowired constructor( assertEquals("common.error.invalid_request", exception.messageKey) } + @Test + @DisplayName("수취인 정보가 없으면 운영 전달 완료 처리할 수 없다") + fun shouldRejectDeliveryCompletionWithoutRecipientAddress() { + val (gift, delivery) = saveGift(GiftStatus.INSPECTION_COMPLETED) + + val exception = assertThrows(SodaException::class.java) { + service.completeDelivery(APPLICATION_NO, NOW) + } + + assertEquals("common.error.invalid_request", exception.messageKey) + assertEquals(GiftStatus.INSPECTION_COMPLETED, gift.status) + assertEquals(null, delivery.deliveredAt) + Mockito.verifyNoInteractions(giftPushService) + } + + @ParameterizedTest + @ValueSource(strings = ["name", "phoneNumber", "zipCode", "address"]) + @DisplayName("수취인 필수 정보에 공백이 있으면 운영 전달 완료 처리할 수 없다") + fun shouldRejectDeliveryCompletionWithBlankRecipientInformation(blankField: String) { + val (gift, delivery) = saveGift(GiftStatus.INSPECTION_COMPLETED) + populateRecipientInformation(delivery) + when (blankField) { + "name" -> delivery.recipientName = " " + "phoneNumber" -> delivery.recipientPhoneNumber = " " + "zipCode" -> delivery.recipientZipCode = " " + "address" -> delivery.recipientAddress = " " + } + + assertThrows(SodaException::class.java) { + service.completeDelivery(APPLICATION_NO, NOW) + } + + assertEquals(GiftStatus.INSPECTION_COMPLETED, gift.status) + assertEquals(null, delivery.deliveredAt) + Mockito.verifyNoInteractions(giftPushService) + } + + private fun populateRecipientInformation(delivery: GiftDelivery) { + delivery.recipientName = "김소다" + delivery.recipientPhoneNumber = "01098765432" + delivery.recipientZipCode = "04524" + delivery.recipientAddress = "서울시 중구" + } + private fun saveGift(status: GiftStatus): Pair { val gift = giftRepository.save( Gift(