feat(gift): 선물 신청 명령 서비스를 추가한다
This commit is contained in:
@@ -0,0 +1,368 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.gift.application
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.can.payment.CanPaymentService
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
|
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.Gift
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftCategoryRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftDelivery
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftDeliveryRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftReview
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftReviewRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftSizePriceRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.domain.GiftSize
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.domain.GiftStatus
|
||||||
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
|
data class GiftApplicationCommand(
|
||||||
|
val recipientMemberId: Long,
|
||||||
|
val senderName: String,
|
||||||
|
val senderPhoneNumber: String,
|
||||||
|
val senderZipCode: String,
|
||||||
|
val senderAddress: String,
|
||||||
|
val senderAddressDetail: String?,
|
||||||
|
val sizeCode: GiftSize,
|
||||||
|
val categoryId: Long,
|
||||||
|
val senderTermsAgreed: Boolean,
|
||||||
|
val senderPrivacyAgreed: Boolean,
|
||||||
|
val damageWaiverAgreed: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GiftApplicationResult(
|
||||||
|
val applicationNo: String,
|
||||||
|
val status: GiftStatus,
|
||||||
|
val statusName: String,
|
||||||
|
val priceCan: Int,
|
||||||
|
val trackingDeadlineAt: LocalDateTime
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GiftCancellationResult(
|
||||||
|
val applicationNo: String,
|
||||||
|
val status: GiftStatus,
|
||||||
|
val statusName: String,
|
||||||
|
val priceCan: Int,
|
||||||
|
val canceledAt: LocalDateTime
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GiftTrackingRegistrationCommand(
|
||||||
|
val courierCompanyName: String,
|
||||||
|
val trackingNumber: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GiftTrackingRegistrationResult(
|
||||||
|
val applicationNo: String,
|
||||||
|
val status: GiftStatus,
|
||||||
|
val statusName: String,
|
||||||
|
val courierCompanyName: String,
|
||||||
|
val trackingNumber: String,
|
||||||
|
val trackingRegisteredAt: LocalDateTime,
|
||||||
|
val recipientAddressDeadlineAt: LocalDateTime
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GiftRecipientAddressRegistrationCommand(
|
||||||
|
val name: String,
|
||||||
|
val phoneNumber: String,
|
||||||
|
val zipCode: String,
|
||||||
|
val address: String,
|
||||||
|
val addressDetail: String?,
|
||||||
|
val recipientTermsAgreed: Boolean,
|
||||||
|
val recipientPrivacyAgreed: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GiftRecipientAddressRegistrationResult(
|
||||||
|
val applicationNo: String,
|
||||||
|
val status: GiftStatus,
|
||||||
|
val statusName: String,
|
||||||
|
val recipientAddressRegisteredAt: LocalDateTime
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GiftDeliveryConfirmationResult(
|
||||||
|
val applicationNo: String,
|
||||||
|
val status: GiftStatus,
|
||||||
|
val statusName: String,
|
||||||
|
val deliveredAt: LocalDateTime
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GiftReviewCommand(
|
||||||
|
val rating: Int,
|
||||||
|
val keywords: List<String>,
|
||||||
|
val comment: String?
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GiftReviewResult(
|
||||||
|
val reviewId: Long,
|
||||||
|
val applicationNo: String,
|
||||||
|
val rating: Int,
|
||||||
|
val keywords: List<String>,
|
||||||
|
val comment: String?,
|
||||||
|
val createdAt: LocalDateTime?
|
||||||
|
)
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class GiftCommandService(
|
||||||
|
private val giftRepository: GiftRepository,
|
||||||
|
private val deliveryRepository: GiftDeliveryRepository,
|
||||||
|
private val reviewRepository: GiftReviewRepository,
|
||||||
|
private val categoryRepository: GiftCategoryRepository,
|
||||||
|
private val sizePriceRepository: GiftSizePriceRepository,
|
||||||
|
private val memberRepository: MemberRepository,
|
||||||
|
private val applicationNoGenerator: GiftApplicationNoGenerator,
|
||||||
|
private val canPaymentService: CanPaymentService,
|
||||||
|
private val giftPushService: GiftPushService,
|
||||||
|
private val now: () -> LocalDateTime = { LocalDateTime.now() }
|
||||||
|
) {
|
||||||
|
@Transactional
|
||||||
|
fun registerGift(member: Member, command: GiftApplicationCommand): GiftApplicationResult {
|
||||||
|
validate(command)
|
||||||
|
val senderMemberId = member.id ?: throw invalidRequest()
|
||||||
|
memberRepository.findCreatorByIdOrNull(command.recipientMemberId) ?: throw invalidRequest()
|
||||||
|
val category = categoryRepository.findByIdOrNull(command.categoryId)?.takeIf { it.isActive } ?: throw invalidRequest()
|
||||||
|
if (category.requiresDamageWaiver && !command.damageWaiverAgreed) throw invalidRequest()
|
||||||
|
val sizePrice = sizePriceRepository.findBySizeCode(command.sizeCode)?.takeIf { it.isActive } ?: throw invalidRequest()
|
||||||
|
val appliedAt = now()
|
||||||
|
val trackingDeadlineAt = appliedAt.plusDays(3)
|
||||||
|
val applicationNo = applicationNoGenerator.generate(appliedAt)
|
||||||
|
val canUsageId = canPaymentService.spendGiftCan(
|
||||||
|
senderMemberId,
|
||||||
|
sizePrice.salePriceCan,
|
||||||
|
member.container.ifBlank { "web" }
|
||||||
|
)
|
||||||
|
val gift = giftRepository.save(
|
||||||
|
Gift(
|
||||||
|
applicationNo = applicationNo,
|
||||||
|
senderMemberId = senderMemberId,
|
||||||
|
recipientMemberId = command.recipientMemberId,
|
||||||
|
status = GiftStatus.RECEIVED,
|
||||||
|
sizeCode = command.sizeCode,
|
||||||
|
categoryId = category.id ?: throw invalidRequest(),
|
||||||
|
categoryNameSnapshot = category.name,
|
||||||
|
salePriceCan = sizePrice.salePriceCan,
|
||||||
|
canUsageId = canUsageId,
|
||||||
|
senderTermsAgreed = command.senderTermsAgreed,
|
||||||
|
senderPrivacyAgreed = command.senderPrivacyAgreed,
|
||||||
|
senderTermsAgreedAt = appliedAt,
|
||||||
|
senderPrivacyAgreedAt = appliedAt,
|
||||||
|
damageWaiverAgreed = command.damageWaiverAgreed
|
||||||
|
)
|
||||||
|
)
|
||||||
|
deliveryRepository.save(
|
||||||
|
GiftDelivery(
|
||||||
|
giftId = gift.id ?: throw invalidRequest(),
|
||||||
|
senderName = command.senderName,
|
||||||
|
senderPhoneNumber = command.senderPhoneNumber,
|
||||||
|
senderZipCode = command.senderZipCode,
|
||||||
|
senderAddress = command.senderAddress,
|
||||||
|
senderAddressDetail = command.senderAddressDetail,
|
||||||
|
trackingDeadlineAt = trackingDeadlineAt
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return GiftApplicationResult(
|
||||||
|
applicationNo = applicationNo,
|
||||||
|
status = GiftStatus.RECEIVED,
|
||||||
|
statusName = GiftStatus.RECEIVED.displayName,
|
||||||
|
priceCan = sizePrice.salePriceCan,
|
||||||
|
trackingDeadlineAt = trackingDeadlineAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun writeReview(member: Member, applicationNo: String, command: GiftReviewCommand): GiftReviewResult {
|
||||||
|
val senderMemberId = member.id ?: throw invalidRequest()
|
||||||
|
val gift = giftRepository.findByApplicationNo(applicationNo) ?: throw invalidRequest()
|
||||||
|
val giftId = gift.id ?: throw invalidRequest()
|
||||||
|
if (
|
||||||
|
gift.senderMemberId != senderMemberId ||
|
||||||
|
gift.status != GiftStatus.DELIVERED ||
|
||||||
|
reviewRepository.findByGiftId(giftId) != null
|
||||||
|
) {
|
||||||
|
throw invalidRequest()
|
||||||
|
}
|
||||||
|
validate(command)
|
||||||
|
|
||||||
|
val review = reviewRepository.save(
|
||||||
|
GiftReview(
|
||||||
|
giftId = giftId,
|
||||||
|
senderMemberId = senderMemberId,
|
||||||
|
rating = command.rating,
|
||||||
|
keywords = command.keywords.joinToString(","),
|
||||||
|
comment = command.comment
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return GiftReviewResult(
|
||||||
|
reviewId = review.id ?: throw invalidRequest(),
|
||||||
|
applicationNo = gift.applicationNo,
|
||||||
|
rating = review.rating,
|
||||||
|
keywords = review.keywords?.takeIf { it.isNotBlank() }?.split(",") ?: emptyList(),
|
||||||
|
comment = review.comment,
|
||||||
|
createdAt = review.createdAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun cancelGift(member: Member, applicationNo: String): GiftCancellationResult {
|
||||||
|
val senderMemberId = member.id ?: throw invalidRequest()
|
||||||
|
val gift = giftRepository.findByApplicationNo(applicationNo) ?: throw invalidRequest()
|
||||||
|
if (gift.senderMemberId != senderMemberId || gift.status != GiftStatus.RECEIVED) throw invalidRequest()
|
||||||
|
|
||||||
|
val canceledAt = now()
|
||||||
|
gift.status = GiftStatus.CANCELED
|
||||||
|
deliveryRepository.findByGiftId(gift.id ?: throw invalidRequest())?.canceledAt = canceledAt
|
||||||
|
canPaymentService.refundGiftCan(senderMemberId, gift.canUsageId)
|
||||||
|
|
||||||
|
return GiftCancellationResult(
|
||||||
|
applicationNo = gift.applicationNo,
|
||||||
|
status = gift.status,
|
||||||
|
statusName = gift.status.displayName,
|
||||||
|
priceCan = gift.salePriceCan,
|
||||||
|
canceledAt = canceledAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun registerTracking(
|
||||||
|
member: Member,
|
||||||
|
applicationNo: String,
|
||||||
|
command: GiftTrackingRegistrationCommand
|
||||||
|
): GiftTrackingRegistrationResult {
|
||||||
|
val senderMemberId = member.id ?: throw invalidRequest()
|
||||||
|
val gift = giftRepository.findByApplicationNo(applicationNo) ?: throw invalidRequest()
|
||||||
|
if (gift.senderMemberId != senderMemberId || gift.status != GiftStatus.RECEIVED) throw invalidRequest()
|
||||||
|
validate(command)
|
||||||
|
val delivery = deliveryRepository.findByGiftId(gift.id ?: throw invalidRequest()) ?: throw invalidRequest()
|
||||||
|
val trackingRegisteredAt = now()
|
||||||
|
val recipientAddressDeadlineAt = trackingRegisteredAt.plusDays(7)
|
||||||
|
|
||||||
|
gift.status = GiftStatus.TRACKING_REGISTERED
|
||||||
|
delivery.courierCompanyName = command.courierCompanyName
|
||||||
|
delivery.trackingNumber = command.trackingNumber
|
||||||
|
delivery.trackingRegisteredAt = trackingRegisteredAt
|
||||||
|
delivery.recipientAddressDeadlineAt = recipientAddressDeadlineAt
|
||||||
|
giftPushService.sendTrackingRegisteredToRecipient(gift.applicationNo, gift.recipientMemberId)
|
||||||
|
|
||||||
|
return GiftTrackingRegistrationResult(
|
||||||
|
applicationNo = gift.applicationNo,
|
||||||
|
status = gift.status,
|
||||||
|
statusName = gift.status.displayName,
|
||||||
|
courierCompanyName = command.courierCompanyName,
|
||||||
|
trackingNumber = command.trackingNumber,
|
||||||
|
trackingRegisteredAt = trackingRegisteredAt,
|
||||||
|
recipientAddressDeadlineAt = recipientAddressDeadlineAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun registerRecipientAddress(
|
||||||
|
member: Member,
|
||||||
|
applicationNo: String,
|
||||||
|
command: GiftRecipientAddressRegistrationCommand
|
||||||
|
): GiftRecipientAddressRegistrationResult {
|
||||||
|
val recipientMemberId = member.id ?: throw invalidRequest()
|
||||||
|
val gift = giftRepository.findByApplicationNo(applicationNo) ?: throw invalidRequest()
|
||||||
|
if (gift.recipientMemberId != recipientMemberId || gift.status !in RECIPIENT_ADDRESS_REGISTRABLE_STATUSES) {
|
||||||
|
throw invalidRequest()
|
||||||
|
}
|
||||||
|
validate(command)
|
||||||
|
val delivery = deliveryRepository.findByGiftId(gift.id ?: throw invalidRequest()) ?: throw invalidRequest()
|
||||||
|
val registeredAt = now()
|
||||||
|
|
||||||
|
delivery.recipientName = command.name
|
||||||
|
delivery.recipientPhoneNumber = command.phoneNumber
|
||||||
|
delivery.recipientZipCode = command.zipCode
|
||||||
|
delivery.recipientAddress = command.address
|
||||||
|
delivery.recipientAddressDetail = command.addressDetail
|
||||||
|
gift.recipientTermsAgreed = command.recipientTermsAgreed
|
||||||
|
gift.recipientPrivacyAgreed = command.recipientPrivacyAgreed
|
||||||
|
gift.recipientTermsAgreedAt = registeredAt
|
||||||
|
gift.recipientPrivacyAgreedAt = registeredAt
|
||||||
|
|
||||||
|
return GiftRecipientAddressRegistrationResult(
|
||||||
|
applicationNo = gift.applicationNo,
|
||||||
|
status = gift.status,
|
||||||
|
statusName = gift.status.displayName,
|
||||||
|
recipientAddressRegisteredAt = registeredAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
fun confirmDelivery(member: Member, applicationNo: String): GiftDeliveryConfirmationResult {
|
||||||
|
val recipientMemberId = member.id ?: throw invalidRequest()
|
||||||
|
val gift = giftRepository.findByApplicationNo(applicationNo) ?: throw invalidRequest()
|
||||||
|
if (gift.recipientMemberId != recipientMemberId || gift.status != GiftStatus.INSPECTION_COMPLETED) {
|
||||||
|
throw invalidRequest()
|
||||||
|
}
|
||||||
|
val delivery = deliveryRepository.findByGiftId(gift.id ?: throw invalidRequest()) ?: throw invalidRequest()
|
||||||
|
val deliveredAt = now()
|
||||||
|
|
||||||
|
gift.status = GiftStatus.DELIVERED
|
||||||
|
delivery.deliveredAt = deliveredAt
|
||||||
|
|
||||||
|
return GiftDeliveryConfirmationResult(
|
||||||
|
applicationNo = gift.applicationNo,
|
||||||
|
status = gift.status,
|
||||||
|
statusName = gift.status.displayName,
|
||||||
|
deliveredAt = deliveredAt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validate(command: GiftApplicationCommand) {
|
||||||
|
if (
|
||||||
|
command.senderName.isBlank() ||
|
||||||
|
command.senderPhoneNumber.isBlank() ||
|
||||||
|
command.senderZipCode.isBlank() ||
|
||||||
|
command.senderAddress.isBlank() ||
|
||||||
|
!command.senderTermsAgreed ||
|
||||||
|
!command.senderPrivacyAgreed
|
||||||
|
) {
|
||||||
|
throw invalidRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validate(command: GiftTrackingRegistrationCommand) {
|
||||||
|
if (
|
||||||
|
command.courierCompanyName.isBlank() ||
|
||||||
|
command.courierCompanyName.length > 50 ||
|
||||||
|
command.trackingNumber.isBlank()
|
||||||
|
) {
|
||||||
|
throw invalidRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validate(command: GiftRecipientAddressRegistrationCommand) {
|
||||||
|
if (
|
||||||
|
command.name.isBlank() ||
|
||||||
|
command.phoneNumber.isBlank() ||
|
||||||
|
command.zipCode.isBlank() ||
|
||||||
|
command.address.isBlank() ||
|
||||||
|
!command.recipientTermsAgreed ||
|
||||||
|
!command.recipientPrivacyAgreed
|
||||||
|
) {
|
||||||
|
throw invalidRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validate(command: GiftReviewCommand) {
|
||||||
|
if (
|
||||||
|
command.rating !in 1..5 ||
|
||||||
|
command.keywords.any { it.length > 255 } ||
|
||||||
|
(command.comment?.length ?: 0) > 255
|
||||||
|
) {
|
||||||
|
throw invalidRequest()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun invalidRequest() = SodaException(messageKey = "common.error.invalid_request")
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
val RECIPIENT_ADDRESS_REGISTRABLE_STATUSES = setOf(
|
||||||
|
GiftStatus.TRACKING_REGISTERED,
|
||||||
|
GiftStatus.ARRIVED_AT_MAILBOX,
|
||||||
|
GiftStatus.INSPECTION_COMPLETED
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,868 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.gift
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.can.CanRepository
|
||||||
|
import kr.co.vividnext.sodalive.can.charge.Charge
|
||||||
|
import kr.co.vividnext.sodalive.can.charge.ChargeRepository
|
||||||
|
import kr.co.vividnext.sodalive.can.payment.CanPaymentService
|
||||||
|
import kr.co.vividnext.sodalive.can.payment.Payment
|
||||||
|
import kr.co.vividnext.sodalive.can.payment.PaymentGateway
|
||||||
|
import kr.co.vividnext.sodalive.can.payment.PaymentStatus
|
||||||
|
import kr.co.vividnext.sodalive.can.use.CanUsage
|
||||||
|
import kr.co.vividnext.sodalive.can.use.UseCan
|
||||||
|
import kr.co.vividnext.sodalive.can.use.UseCanCalculate
|
||||||
|
import kr.co.vividnext.sodalive.can.use.UseCanCalculateRepository
|
||||||
|
import kr.co.vividnext.sodalive.can.use.UseCanRepository
|
||||||
|
import kr.co.vividnext.sodalive.common.CountryContext
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
|
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||||
|
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||||
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
|
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.Gift
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftCategory
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftCategoryRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftDelivery
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftDeliveryRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftReview
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftReviewRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftSizePrice
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.adapter.out.persistence.GiftSizePriceRepository
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftApplicationCommand
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftApplicationNoGenerator
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftCancellationResult
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftCommandService
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftDeliveryConfirmationResult
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftPushService
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftRecipientAddressRegistrationCommand
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftRecipientAddressRegistrationResult
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftReviewCommand
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftReviewResult
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftTrackingRegistrationCommand
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.application.GiftTrackingRegistrationResult
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.domain.GiftSize
|
||||||
|
import kr.co.vividnext.sodalive.v2.gift.domain.GiftStatus
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
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.MethodSource
|
||||||
|
import org.mockito.Mockito
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.util.Optional
|
||||||
|
|
||||||
|
class GiftCommandServiceTest {
|
||||||
|
@Test
|
||||||
|
@DisplayName("선물 캔 사용은 한 번만 환불할 수 있다")
|
||||||
|
fun shouldSpendAndRefundGiftCanOnlyOnce() {
|
||||||
|
// Given: 충전 캔을 보유한 선물 발신자와 결제 서비스를 준비한다.
|
||||||
|
val member = Member(password = "password", nickname = "sender")
|
||||||
|
member.id = MEMBER_ID
|
||||||
|
member.pgChargeCan = INITIAL_CAN
|
||||||
|
val charge = Charge(chargeCan = INITIAL_CAN, rewardCan = 0)
|
||||||
|
charge.id = CHARGE_ID
|
||||||
|
charge.member = member
|
||||||
|
charge.payment = Payment(status = PaymentStatus.COMPLETE, paymentGateway = PaymentGateway.PG)
|
||||||
|
val fixture = CanPaymentFixture(member, charge)
|
||||||
|
|
||||||
|
// When: 선물용 캔을 사용한 뒤 해당 사용 내역을 환불한다.
|
||||||
|
val useCanId = fixture.service.spendGiftCan(
|
||||||
|
memberId = MEMBER_ID,
|
||||||
|
needCan = GIFT_PRICE_CAN,
|
||||||
|
container = "web"
|
||||||
|
)
|
||||||
|
val afterSpendCan = member.getChargeCan("web") + member.getRewardCan("web")
|
||||||
|
fixture.service.refundGiftCan(memberId = MEMBER_ID, useCanId = useCanId)
|
||||||
|
val afterRefundCan = member.getChargeCan("web") + member.getRewardCan("web")
|
||||||
|
|
||||||
|
// Then: 발신자와 GIFT 용도가 저장되고, 잔액이 복원되며 재환불은 거부된다.
|
||||||
|
assertEquals(CanUsage.GIFT, fixture.savedUseCan.canUsage)
|
||||||
|
assertEquals(member, fixture.savedUseCan.member)
|
||||||
|
assertEquals(INITIAL_CAN - GIFT_PRICE_CAN, afterSpendCan)
|
||||||
|
assertEquals(INITIAL_CAN, afterRefundCan)
|
||||||
|
assertEquals(true, fixture.savedUseCan.isRefund)
|
||||||
|
assertThrows(SodaException::class.java) {
|
||||||
|
fixture.service.refundGiftCan(memberId = MEMBER_ID, useCanId = useCanId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("선물 신청은 가격과 약관 동의, 배송 기한을 스냅샷으로 저장하고 캔을 차감한다")
|
||||||
|
fun shouldRegisterGiftWithPriceAgreementAndDeliverySnapshots() {
|
||||||
|
// Given: 활성 선물 카테고리와 가격, 발신자 및 수신 크리에이터를 준비한다.
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
|
||||||
|
// When: 팬이 선물을 신청한다.
|
||||||
|
val result = fixture.service.registerGift(fixture.sender, validGiftApplicationCommand())
|
||||||
|
|
||||||
|
// Then: 신청 정보와 배송 기한을 저장하고 판매가만큼 캔을 차감한다.
|
||||||
|
assertEquals(APPLICATION_NO, result.applicationNo)
|
||||||
|
assertEquals(GiftStatus.RECEIVED, result.status)
|
||||||
|
assertEquals(GiftStatus.RECEIVED.displayName, result.statusName)
|
||||||
|
assertEquals(SALE_PRICE_CAN, result.priceCan)
|
||||||
|
assertEquals(NOW.plusDays(3), result.trackingDeadlineAt)
|
||||||
|
assertEquals(SENDER_ID, fixture.savedGift.senderMemberId)
|
||||||
|
assertEquals(RECIPIENT_ID, fixture.savedGift.recipientMemberId)
|
||||||
|
assertEquals(GiftStatus.RECEIVED, fixture.savedGift.status)
|
||||||
|
assertEquals(GiftSize.SMALL, fixture.savedGift.sizeCode)
|
||||||
|
assertEquals(CATEGORY_ID, fixture.savedGift.categoryId)
|
||||||
|
assertEquals("인형", fixture.savedGift.categoryNameSnapshot)
|
||||||
|
assertEquals(SALE_PRICE_CAN, fixture.savedGift.salePriceCan)
|
||||||
|
assertEquals(USE_CAN_ID, fixture.savedGift.canUsageId)
|
||||||
|
assertEquals(true, fixture.savedGift.senderTermsAgreed)
|
||||||
|
assertEquals(true, fixture.savedGift.senderPrivacyAgreed)
|
||||||
|
assertEquals(NOW, fixture.savedGift.senderTermsAgreedAt)
|
||||||
|
assertEquals(NOW, fixture.savedGift.senderPrivacyAgreedAt)
|
||||||
|
assertEquals(true, fixture.savedGift.damageWaiverAgreed)
|
||||||
|
assertEquals(GIFT_ID, fixture.savedDelivery.giftId)
|
||||||
|
assertEquals("홍길동", fixture.savedDelivery.senderName)
|
||||||
|
assertEquals("01012345678", fixture.savedDelivery.senderPhoneNumber)
|
||||||
|
assertEquals("06234", fixture.savedDelivery.senderZipCode)
|
||||||
|
assertEquals("서울시 강남구", fixture.savedDelivery.senderAddress)
|
||||||
|
assertEquals("101동 1001호", fixture.savedDelivery.senderAddressDetail)
|
||||||
|
assertEquals(NOW.plusDays(3), fixture.savedDelivery.trackingDeadlineAt)
|
||||||
|
Mockito.verify(fixture.canPaymentService).spendGiftCan(SENDER_ID, SALE_PRICE_CAN, "aos")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("보낸 팬은 운송장 등록 전 선물을 취소하고 전액 환불받는다")
|
||||||
|
fun shouldCancelReceivedGiftAndRefundOnce() {
|
||||||
|
// Given: 접수 상태의 선물과 발신자 배송 정보를 준비한다.
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForCancellation()
|
||||||
|
|
||||||
|
// When: 보낸 팬이 선물을 취소한다.
|
||||||
|
val result = fixture.service.cancelGift(fixture.sender, APPLICATION_NO)
|
||||||
|
|
||||||
|
// Then: 선물과 배송 정보에 취소 시각을 저장하고 한 번만 환불한다.
|
||||||
|
assertEquals(
|
||||||
|
GiftCancellationResult(
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
status = GiftStatus.CANCELED,
|
||||||
|
statusName = GiftStatus.CANCELED.displayName,
|
||||||
|
priceCan = SALE_PRICE_CAN,
|
||||||
|
canceledAt = NOW
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
assertEquals(GiftStatus.CANCELED, fixture.cancellationGift.status)
|
||||||
|
assertEquals(NOW, fixture.cancellationDelivery.canceledAt)
|
||||||
|
Mockito.verify(fixture.canPaymentService).refundGiftCan(SENDER_ID, USE_CAN_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("보낸 팬은 접수된 선물의 운송장을 등록하고 크리에이터 배송지 입력 기한을 생성한다")
|
||||||
|
fun shouldRegisterTrackingForReceivedGift() {
|
||||||
|
// Given: 접수 상태의 선물과 발신자 배송 정보를 준비한다.
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForTracking()
|
||||||
|
|
||||||
|
// When: 보낸 팬이 택배사와 운송장 번호를 등록한다.
|
||||||
|
val result = fixture.service.registerTracking(
|
||||||
|
fixture.sender,
|
||||||
|
APPLICATION_NO,
|
||||||
|
validGiftTrackingRegistrationCommand()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Then: 발송 확인 상태와 운송장 정보, 수신자 주소 입력 기한을 저장한다.
|
||||||
|
assertEquals(
|
||||||
|
GiftTrackingRegistrationResult(
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
status = GiftStatus.TRACKING_REGISTERED,
|
||||||
|
statusName = GiftStatus.TRACKING_REGISTERED.displayName,
|
||||||
|
courierCompanyName = "CJ대한통운",
|
||||||
|
trackingNumber = "1234567890",
|
||||||
|
trackingRegisteredAt = NOW,
|
||||||
|
recipientAddressDeadlineAt = NOW.plusDays(7)
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
assertEquals(GiftStatus.TRACKING_REGISTERED, fixture.trackingGift.status)
|
||||||
|
assertEquals("CJ대한통운", fixture.trackingDelivery.courierCompanyName)
|
||||||
|
assertEquals("1234567890", fixture.trackingDelivery.trackingNumber)
|
||||||
|
assertEquals(NOW, fixture.trackingDelivery.trackingRegisteredAt)
|
||||||
|
assertEquals(NOW.plusDays(7), fixture.trackingDelivery.recipientAddressDeadlineAt)
|
||||||
|
Mockito.verify(fixture.giftPushService).sendTrackingRegisteredToRecipient(APPLICATION_NO, RECIPIENT_ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("recipientAddressRegistrableStatuses")
|
||||||
|
@DisplayName("받는 크리에이터는 운송장 등록 이후 종료 전 상태에서 주소와 수령 동의를 등록한다")
|
||||||
|
fun shouldRegisterRecipientAddressAndAgreements(status: GiftStatus) {
|
||||||
|
// Given: 주소 입력이 허용된 선물과 받는 크리에이터를 준비한다.
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForRecipientAddress(status = status)
|
||||||
|
|
||||||
|
// When: 받는 크리에이터가 배송지와 수령 약관 동의를 등록한다.
|
||||||
|
val result = fixture.service.registerRecipientAddress(
|
||||||
|
fixture.creator,
|
||||||
|
APPLICATION_NO,
|
||||||
|
validGiftRecipientAddressRegistrationCommand()
|
||||||
|
)
|
||||||
|
|
||||||
|
// Then: 주소 스냅샷과 두 동의 시각을 저장하고 현재 상태를 반환한다.
|
||||||
|
assertEquals(
|
||||||
|
GiftRecipientAddressRegistrationResult(
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
status = status,
|
||||||
|
statusName = status.displayName,
|
||||||
|
recipientAddressRegisteredAt = NOW
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
assertEquals("김소다", fixture.recipientAddressDelivery.recipientName)
|
||||||
|
assertEquals("01098765432", fixture.recipientAddressDelivery.recipientPhoneNumber)
|
||||||
|
assertEquals("04524", fixture.recipientAddressDelivery.recipientZipCode)
|
||||||
|
assertEquals("서울시 중구", fixture.recipientAddressDelivery.recipientAddress)
|
||||||
|
assertEquals("202호", fixture.recipientAddressDelivery.recipientAddressDetail)
|
||||||
|
assertEquals(true, fixture.recipientAddressGift.recipientTermsAgreed)
|
||||||
|
assertEquals(true, fixture.recipientAddressGift.recipientPrivacyAgreed)
|
||||||
|
assertEquals(NOW, fixture.recipientAddressGift.recipientTermsAgreedAt)
|
||||||
|
assertEquals(NOW, fixture.recipientAddressGift.recipientPrivacyAgreedAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("받는 크리에이터는 검수 완료 선물의 수령을 확인하고 전달 완료 시각을 저장한다")
|
||||||
|
fun shouldConfirmDeliveryForInspectionCompletedGift() {
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForDeliveryConfirmation()
|
||||||
|
|
||||||
|
val result = fixture.service.confirmDelivery(fixture.creator, APPLICATION_NO)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
GiftDeliveryConfirmationResult(
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
status = GiftStatus.DELIVERED,
|
||||||
|
statusName = GiftStatus.DELIVERED.displayName,
|
||||||
|
deliveredAt = NOW
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
assertEquals(GiftStatus.DELIVERED, fixture.deliveryConfirmationGift.status)
|
||||||
|
assertEquals(NOW, fixture.deliveryConfirmationDelivery.deliveredAt)
|
||||||
|
Mockito.verifyNoInteractions(fixture.giftPushService)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("보낸 팬은 전달 완료 선물에 리뷰를 한 번 작성한다")
|
||||||
|
fun shouldWriteReviewForDeliveredGiftBySender() {
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForReview()
|
||||||
|
|
||||||
|
val result = fixture.service.writeReview(fixture.sender, APPLICATION_NO, validGiftReviewCommand())
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
GiftReviewResult(
|
||||||
|
reviewId = REVIEW_ID,
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
rating = 5,
|
||||||
|
keywords = listOf("배송이 빨라요", "안내가 친절해요"),
|
||||||
|
comment = "선물 전달 과정이 만족스러웠습니다.",
|
||||||
|
createdAt = NOW
|
||||||
|
),
|
||||||
|
result
|
||||||
|
)
|
||||||
|
assertEquals(GIFT_ID, fixture.savedReview.giftId)
|
||||||
|
assertEquals(SENDER_ID, fixture.savedReview.senderMemberId)
|
||||||
|
assertEquals(5, fixture.savedReview.rating)
|
||||||
|
assertEquals("배송이 빨라요,안내가 친절해요", fixture.savedReview.keywords)
|
||||||
|
assertEquals("선물 전달 과정이 만족스러웠습니다.", fixture.savedReview.comment)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("invalidGiftReviewScenarios")
|
||||||
|
@DisplayName("리뷰 작성은 보낸 팬의 전달 완료 선물, 1회, 유효한 별점과 내용만 허용한다")
|
||||||
|
fun shouldRejectInvalidGiftReview(scenario: InvalidGiftReviewScenario) {
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForReview(
|
||||||
|
status = scenario.status,
|
||||||
|
senderMemberId = scenario.senderMemberId,
|
||||||
|
reviewExists = scenario.reviewExists
|
||||||
|
)
|
||||||
|
val requester = Member(password = "password", nickname = "requester").apply { id = scenario.requesterMemberId }
|
||||||
|
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
fixture.service.writeReview(requester, APPLICATION_NO, scenario.command)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("common.error.invalid_request", exception.messageKey)
|
||||||
|
Mockito.verify(fixture.reviewRepository, Mockito.never()).save(Mockito.any(GiftReview::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("invalidGiftDeliveryConfirmationScenarios")
|
||||||
|
@DisplayName("수령 확인은 받는 크리에이터의 검수 완료 선물에만 가능하고 배송 정보가 필요하다")
|
||||||
|
fun shouldRejectInvalidGiftDeliveryConfirmation(scenario: InvalidGiftDeliveryConfirmationScenario) {
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForDeliveryConfirmation(
|
||||||
|
status = scenario.status,
|
||||||
|
recipientMemberId = scenario.recipientMemberId,
|
||||||
|
deliveryExists = scenario.deliveryExists
|
||||||
|
)
|
||||||
|
val requester = Member(password = "password", nickname = "requester").apply { id = scenario.requesterMemberId }
|
||||||
|
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
fixture.service.confirmDelivery(requester, APPLICATION_NO)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("common.error.invalid_request", exception.messageKey)
|
||||||
|
assertEquals(scenario.status, fixture.deliveryConfirmationGift.status)
|
||||||
|
assertEquals(null, fixture.deliveryConfirmationDelivery.deliveredAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("invalidGiftRecipientAddressRegistrationScenarios")
|
||||||
|
@DisplayName("수령자 주소 등록은 받는 크리에이터, 허용 상태, 필수 주소와 두 동의가 필요하다")
|
||||||
|
fun shouldRejectInvalidGiftRecipientAddressRegistration(scenario: InvalidGiftRecipientAddressRegistrationScenario) {
|
||||||
|
// Given: 권한, 상태 또는 입력값이 유효하지 않은 선물을 준비한다.
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForRecipientAddress(
|
||||||
|
status = scenario.status,
|
||||||
|
recipientMemberId = scenario.recipientMemberId,
|
||||||
|
deliveryExists = scenario.deliveryExists
|
||||||
|
)
|
||||||
|
val requester = Member(password = "password", nickname = "requester").apply { id = scenario.requesterMemberId }
|
||||||
|
|
||||||
|
// When: 배송지 등록을 요청한다.
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
fixture.service.registerRecipientAddress(requester, APPLICATION_NO, scenario.command)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then: 공통 요청 오류를 반환하고 선물 상태와 수령 동의를 바꾸지 않는다.
|
||||||
|
assertEquals("common.error.invalid_request", exception.messageKey)
|
||||||
|
assertEquals(scenario.status, fixture.recipientAddressGift.status)
|
||||||
|
assertEquals(false, fixture.recipientAddressGift.recipientTermsAgreed)
|
||||||
|
assertEquals(false, fixture.recipientAddressGift.recipientPrivacyAgreed)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("invalidGiftTrackingRegistrationScenarios")
|
||||||
|
@DisplayName("운송장 등록은 보낸 팬의 접수 상태에서 유효한 택배사와 운송장 번호가 있어야 한다")
|
||||||
|
fun shouldRejectInvalidGiftTrackingRegistration(scenario: InvalidGiftTrackingRegistrationScenario) {
|
||||||
|
// Given: 운송장 등록 권한, 상태, 입력값 또는 배송 정보가 유효하지 않은 선물을 준비한다.
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForTracking(scenario.status, scenario.senderMemberId, scenario.deliveryExists)
|
||||||
|
val requester = Member(password = "password", nickname = "requester").apply { id = scenario.requesterMemberId }
|
||||||
|
|
||||||
|
// When: 운송장 등록을 요청한다.
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
fixture.service.registerTracking(requester, APPLICATION_NO, scenario.command)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then: 공통 요청 오류를 반환하고 선물 상태를 바꾸지 않는다.
|
||||||
|
assertEquals("common.error.invalid_request", exception.messageKey)
|
||||||
|
assertEquals(scenario.status, fixture.trackingGift.status)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("invalidGiftCancellationScenarios")
|
||||||
|
@DisplayName("선물 취소는 보낸 팬의 접수 상태에서만 가능하다")
|
||||||
|
fun shouldRejectGiftCancellationForInvalidSenderOrStatus(scenario: InvalidGiftCancellationScenario) {
|
||||||
|
// Given: 취소 권한 또는 상태가 유효하지 않은 선물을 준비한다.
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.prepareGiftForCancellation(scenario.status, scenario.senderMemberId)
|
||||||
|
val requester = Member(password = "password", nickname = "requester").apply { id = scenario.requesterMemberId }
|
||||||
|
|
||||||
|
// When: 취소를 요청한다.
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
fixture.service.cancelGift(requester, APPLICATION_NO)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then: 환불하지 않고 공통 요청 오류를 반환한다.
|
||||||
|
assertEquals("common.error.invalid_request", exception.messageKey)
|
||||||
|
Mockito.verify(fixture.canPaymentService, Mockito.never()).refundGiftCan(
|
||||||
|
Mockito.anyLong(),
|
||||||
|
Mockito.anyLong()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ParameterizedTest
|
||||||
|
@MethodSource("invalidGiftApplicationScenarios")
|
||||||
|
@DisplayName("선물 신청은 필수 발신자 정보, 동의, 활성 옵션 및 수신 크리에이터를 검증한다")
|
||||||
|
fun shouldRejectInvalidGiftApplication(scenario: InvalidGiftApplicationScenario) {
|
||||||
|
// Given: 하나의 신청 조건만 유효하지 않은 선물 신청을 준비한다.
|
||||||
|
val fixture = GiftApplicationFixture()
|
||||||
|
fixture.category.isActive = scenario.categoryActive
|
||||||
|
fixture.category.requiresDamageWaiver = scenario.requiresDamageWaiver
|
||||||
|
fixture.sizePrice.isActive = scenario.sizePriceActive
|
||||||
|
fixture.setCreatorExists(scenario.creatorExists)
|
||||||
|
|
||||||
|
// When: 유효하지 않은 신청을 등록한다.
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
fixture.service.registerGift(fixture.sender, scenario.command)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then: 캔을 차감하지 않고 공통 요청 오류를 반환한다.
|
||||||
|
assertEquals("common.error.invalid_request", exception.messageKey)
|
||||||
|
Mockito.verifyNoInteractions(fixture.canPaymentService)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CanPaymentFixture(member: Member, charge: Charge) {
|
||||||
|
private val canRepository = Mockito.mock(CanRepository::class.java)
|
||||||
|
private val memberRepository = Mockito.mock(MemberRepository::class.java)
|
||||||
|
private val chargeRepository = Mockito.mock(ChargeRepository::class.java)
|
||||||
|
private val useCanRepository = Mockito.mock(UseCanRepository::class.java)
|
||||||
|
private val useCanCalculateRepository = Mockito.mock(UseCanCalculateRepository::class.java)
|
||||||
|
private val useCanCalculates = mutableListOf<UseCanCalculate>()
|
||||||
|
lateinit var savedUseCan: UseCan
|
||||||
|
private set
|
||||||
|
|
||||||
|
val service = CanPaymentService(
|
||||||
|
repository = canRepository,
|
||||||
|
memberRepository = memberRepository,
|
||||||
|
chargeRepository = chargeRepository,
|
||||||
|
useCanRepository = useCanRepository,
|
||||||
|
useCanCalculateRepository = useCanCalculateRepository,
|
||||||
|
messageSource = SodaMessageSource(),
|
||||||
|
langContext = LangContext(),
|
||||||
|
countryContext = CountryContext()
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
Mockito.`when`(memberRepository.findById(MEMBER_ID)).thenReturn(Optional.of(member))
|
||||||
|
Mockito.`when`(
|
||||||
|
chargeRepository.getOldestChargeWhereRewardCanGreaterThan0(0L, MEMBER_ID, "web")
|
||||||
|
).thenReturn(null)
|
||||||
|
Mockito.`when`(
|
||||||
|
chargeRepository.getOldestChargeWhereChargeCanGreaterThan0(0L, MEMBER_ID, "web")
|
||||||
|
).thenReturn(charge)
|
||||||
|
Mockito.`when`(useCanRepository.save(Mockito.any(UseCan::class.java))).thenAnswer { invocation ->
|
||||||
|
invocation.getArgument<UseCan>(0).apply {
|
||||||
|
id = USE_CAN_ID
|
||||||
|
savedUseCan = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mockito.`when`(useCanRepository.findById(USE_CAN_ID)).thenAnswer { Optional.of(savedUseCan) }
|
||||||
|
Mockito.`when`(useCanCalculateRepository.save(Mockito.any(UseCanCalculate::class.java))).thenAnswer {
|
||||||
|
invocation ->
|
||||||
|
invocation.getArgument<UseCanCalculate>(0).also(useCanCalculates::add)
|
||||||
|
}
|
||||||
|
Mockito.`when`(useCanCalculateRepository.findByUseCanIdAndStatus(USE_CAN_ID)).thenReturn(useCanCalculates)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class GiftApplicationFixture {
|
||||||
|
val giftRepository = Mockito.mock(GiftRepository::class.java)
|
||||||
|
val deliveryRepository = Mockito.mock(GiftDeliveryRepository::class.java)
|
||||||
|
val reviewRepository = Mockito.mock(GiftReviewRepository::class.java)
|
||||||
|
val categoryRepository = Mockito.mock(GiftCategoryRepository::class.java)
|
||||||
|
val sizePriceRepository = Mockito.mock(GiftSizePriceRepository::class.java)
|
||||||
|
val memberRepository = Mockito.mock(MemberRepository::class.java)
|
||||||
|
val applicationNoGenerator = Mockito.mock(GiftApplicationNoGenerator::class.java)
|
||||||
|
val canPaymentService = Mockito.mock(CanPaymentService::class.java)
|
||||||
|
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 sizePrice = GiftSizePrice(GiftSize.SMALL, BASE_PRICE_CAN, SALE_PRICE_CAN, true)
|
||||||
|
lateinit var savedGift: Gift
|
||||||
|
lateinit var savedDelivery: GiftDelivery
|
||||||
|
lateinit var cancellationGift: Gift
|
||||||
|
lateinit var cancellationDelivery: GiftDelivery
|
||||||
|
lateinit var trackingGift: Gift
|
||||||
|
lateinit var trackingDelivery: GiftDelivery
|
||||||
|
lateinit var recipientAddressGift: Gift
|
||||||
|
lateinit var recipientAddressDelivery: GiftDelivery
|
||||||
|
lateinit var deliveryConfirmationGift: Gift
|
||||||
|
lateinit var deliveryConfirmationDelivery: GiftDelivery
|
||||||
|
lateinit var reviewGift: Gift
|
||||||
|
lateinit var savedReview: GiftReview
|
||||||
|
|
||||||
|
val service = GiftCommandService(
|
||||||
|
giftRepository = giftRepository,
|
||||||
|
deliveryRepository = deliveryRepository,
|
||||||
|
reviewRepository = reviewRepository,
|
||||||
|
categoryRepository = categoryRepository,
|
||||||
|
sizePriceRepository = sizePriceRepository,
|
||||||
|
memberRepository = memberRepository,
|
||||||
|
applicationNoGenerator = applicationNoGenerator,
|
||||||
|
canPaymentService = canPaymentService,
|
||||||
|
giftPushService = giftPushService,
|
||||||
|
now = { NOW }
|
||||||
|
)
|
||||||
|
|
||||||
|
init {
|
||||||
|
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`(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 {
|
||||||
|
id = GIFT_ID
|
||||||
|
savedGift = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Mockito.`when`(deliveryRepository.save(Mockito.any(GiftDelivery::class.java))).thenAnswer { invocation ->
|
||||||
|
invocation.getArgument<GiftDelivery>(0).also { savedDelivery = it }
|
||||||
|
}
|
||||||
|
Mockito.`when`(reviewRepository.save(Mockito.any(GiftReview::class.java))).thenAnswer { invocation ->
|
||||||
|
invocation.getArgument<GiftReview>(0).apply {
|
||||||
|
id = REVIEW_ID
|
||||||
|
createdAt = NOW
|
||||||
|
savedReview = this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setCreatorExists(exists: Boolean) {
|
||||||
|
Mockito.`when`(memberRepository.findCreatorByIdOrNull(RECIPIENT_ID)).thenReturn(creator.takeIf { exists })
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prepareGiftForCancellation(
|
||||||
|
status: GiftStatus = GiftStatus.RECEIVED,
|
||||||
|
senderMemberId: Long = SENDER_ID
|
||||||
|
) {
|
||||||
|
cancellationGift = Gift(
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
senderMemberId = senderMemberId,
|
||||||
|
recipientMemberId = RECIPIENT_ID,
|
||||||
|
status = status,
|
||||||
|
sizeCode = GiftSize.SMALL,
|
||||||
|
categoryId = CATEGORY_ID,
|
||||||
|
categoryNameSnapshot = "인형",
|
||||||
|
salePriceCan = SALE_PRICE_CAN,
|
||||||
|
canUsageId = USE_CAN_ID,
|
||||||
|
senderTermsAgreed = true,
|
||||||
|
senderPrivacyAgreed = true,
|
||||||
|
senderTermsAgreedAt = NOW,
|
||||||
|
senderPrivacyAgreedAt = NOW,
|
||||||
|
damageWaiverAgreed = true
|
||||||
|
).apply { id = GIFT_ID }
|
||||||
|
cancellationDelivery = GiftDelivery(
|
||||||
|
giftId = GIFT_ID,
|
||||||
|
senderName = "홍길동",
|
||||||
|
senderPhoneNumber = "01012345678",
|
||||||
|
senderZipCode = "06234",
|
||||||
|
senderAddress = "서울시 강남구",
|
||||||
|
trackingDeadlineAt = NOW.plusDays(3)
|
||||||
|
)
|
||||||
|
Mockito.`when`(giftRepository.findByApplicationNo(APPLICATION_NO)).thenReturn(cancellationGift)
|
||||||
|
Mockito.`when`(deliveryRepository.findByGiftId(GIFT_ID)).thenReturn(cancellationDelivery)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prepareGiftForTracking(
|
||||||
|
status: GiftStatus = GiftStatus.RECEIVED,
|
||||||
|
senderMemberId: Long = SENDER_ID,
|
||||||
|
deliveryExists: Boolean = true
|
||||||
|
) {
|
||||||
|
trackingGift = Gift(
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
senderMemberId = senderMemberId,
|
||||||
|
recipientMemberId = RECIPIENT_ID,
|
||||||
|
status = status,
|
||||||
|
sizeCode = GiftSize.SMALL,
|
||||||
|
categoryId = CATEGORY_ID,
|
||||||
|
categoryNameSnapshot = "인형",
|
||||||
|
salePriceCan = SALE_PRICE_CAN,
|
||||||
|
canUsageId = USE_CAN_ID,
|
||||||
|
senderTermsAgreed = true,
|
||||||
|
senderPrivacyAgreed = true,
|
||||||
|
senderTermsAgreedAt = NOW,
|
||||||
|
senderPrivacyAgreedAt = NOW,
|
||||||
|
damageWaiverAgreed = true
|
||||||
|
).apply { id = GIFT_ID }
|
||||||
|
trackingDelivery = GiftDelivery(
|
||||||
|
giftId = GIFT_ID,
|
||||||
|
senderName = "홍길동",
|
||||||
|
senderPhoneNumber = "01012345678",
|
||||||
|
senderZipCode = "06234",
|
||||||
|
senderAddress = "서울시 강남구",
|
||||||
|
trackingDeadlineAt = NOW.plusDays(3)
|
||||||
|
)
|
||||||
|
Mockito.`when`(giftRepository.findByApplicationNo(APPLICATION_NO)).thenReturn(trackingGift)
|
||||||
|
Mockito.`when`(deliveryRepository.findByGiftId(GIFT_ID)).thenReturn(
|
||||||
|
trackingDelivery.takeIf { deliveryExists }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prepareGiftForRecipientAddress(
|
||||||
|
status: GiftStatus = GiftStatus.TRACKING_REGISTERED,
|
||||||
|
recipientMemberId: Long = RECIPIENT_ID,
|
||||||
|
deliveryExists: Boolean = true
|
||||||
|
) {
|
||||||
|
recipientAddressGift = Gift(
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
senderMemberId = SENDER_ID,
|
||||||
|
recipientMemberId = recipientMemberId,
|
||||||
|
status = status,
|
||||||
|
sizeCode = GiftSize.SMALL,
|
||||||
|
categoryId = CATEGORY_ID,
|
||||||
|
categoryNameSnapshot = "인형",
|
||||||
|
salePriceCan = SALE_PRICE_CAN,
|
||||||
|
canUsageId = USE_CAN_ID,
|
||||||
|
senderTermsAgreed = true,
|
||||||
|
senderPrivacyAgreed = true,
|
||||||
|
senderTermsAgreedAt = NOW,
|
||||||
|
senderPrivacyAgreedAt = NOW,
|
||||||
|
damageWaiverAgreed = true
|
||||||
|
).apply { id = GIFT_ID }
|
||||||
|
recipientAddressDelivery = GiftDelivery(
|
||||||
|
giftId = GIFT_ID,
|
||||||
|
senderName = "홍길동",
|
||||||
|
senderPhoneNumber = "01012345678",
|
||||||
|
senderZipCode = "06234",
|
||||||
|
senderAddress = "서울시 강남구",
|
||||||
|
trackingDeadlineAt = NOW.plusDays(3)
|
||||||
|
)
|
||||||
|
Mockito.`when`(giftRepository.findByApplicationNo(APPLICATION_NO)).thenReturn(recipientAddressGift)
|
||||||
|
Mockito.`when`(deliveryRepository.findByGiftId(GIFT_ID)).thenReturn(
|
||||||
|
recipientAddressDelivery.takeIf { deliveryExists }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prepareGiftForDeliveryConfirmation(
|
||||||
|
status: GiftStatus = GiftStatus.INSPECTION_COMPLETED,
|
||||||
|
recipientMemberId: Long = RECIPIENT_ID,
|
||||||
|
deliveryExists: Boolean = true
|
||||||
|
) {
|
||||||
|
deliveryConfirmationGift = Gift(
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
senderMemberId = SENDER_ID,
|
||||||
|
recipientMemberId = recipientMemberId,
|
||||||
|
status = status,
|
||||||
|
sizeCode = GiftSize.SMALL,
|
||||||
|
categoryId = CATEGORY_ID,
|
||||||
|
categoryNameSnapshot = "인형",
|
||||||
|
salePriceCan = SALE_PRICE_CAN,
|
||||||
|
canUsageId = USE_CAN_ID,
|
||||||
|
senderTermsAgreed = true,
|
||||||
|
senderPrivacyAgreed = true,
|
||||||
|
senderTermsAgreedAt = NOW,
|
||||||
|
senderPrivacyAgreedAt = NOW,
|
||||||
|
damageWaiverAgreed = true
|
||||||
|
).apply { id = GIFT_ID }
|
||||||
|
deliveryConfirmationDelivery = GiftDelivery(
|
||||||
|
giftId = GIFT_ID,
|
||||||
|
senderName = "홍길동",
|
||||||
|
senderPhoneNumber = "01012345678",
|
||||||
|
senderZipCode = "06234",
|
||||||
|
senderAddress = "서울시 강남구",
|
||||||
|
trackingDeadlineAt = NOW.plusDays(3)
|
||||||
|
)
|
||||||
|
Mockito.`when`(giftRepository.findByApplicationNo(APPLICATION_NO)).thenReturn(deliveryConfirmationGift)
|
||||||
|
Mockito.`when`(deliveryRepository.findByGiftId(GIFT_ID)).thenReturn(
|
||||||
|
deliveryConfirmationDelivery.takeIf { deliveryExists }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prepareGiftForReview(
|
||||||
|
status: GiftStatus = GiftStatus.DELIVERED,
|
||||||
|
senderMemberId: Long = SENDER_ID,
|
||||||
|
reviewExists: Boolean = false
|
||||||
|
) {
|
||||||
|
reviewGift = Gift(
|
||||||
|
applicationNo = APPLICATION_NO,
|
||||||
|
senderMemberId = senderMemberId,
|
||||||
|
recipientMemberId = RECIPIENT_ID,
|
||||||
|
status = status,
|
||||||
|
sizeCode = GiftSize.SMALL,
|
||||||
|
categoryId = CATEGORY_ID,
|
||||||
|
categoryNameSnapshot = "인형",
|
||||||
|
salePriceCan = SALE_PRICE_CAN,
|
||||||
|
canUsageId = USE_CAN_ID,
|
||||||
|
senderTermsAgreed = true,
|
||||||
|
senderPrivacyAgreed = true,
|
||||||
|
senderTermsAgreedAt = NOW,
|
||||||
|
senderPrivacyAgreedAt = NOW,
|
||||||
|
damageWaiverAgreed = true
|
||||||
|
).apply { id = GIFT_ID }
|
||||||
|
Mockito.`when`(giftRepository.findByApplicationNo(APPLICATION_NO)).thenReturn(reviewGift)
|
||||||
|
Mockito.`when`(reviewRepository.findByGiftId(GIFT_ID)).thenReturn(
|
||||||
|
GiftReview(GIFT_ID, SENDER_ID, 5).takeIf { reviewExists }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class InvalidGiftApplicationScenario(
|
||||||
|
val command: GiftApplicationCommand,
|
||||||
|
val categoryActive: Boolean = true,
|
||||||
|
val requiresDamageWaiver: Boolean = false,
|
||||||
|
val sizePriceActive: Boolean = true,
|
||||||
|
val creatorExists: Boolean = true
|
||||||
|
)
|
||||||
|
|
||||||
|
data class InvalidGiftCancellationScenario(
|
||||||
|
val requesterMemberId: Long,
|
||||||
|
val senderMemberId: Long,
|
||||||
|
val status: GiftStatus
|
||||||
|
)
|
||||||
|
|
||||||
|
data class InvalidGiftTrackingRegistrationScenario(
|
||||||
|
val requesterMemberId: Long = SENDER_ID,
|
||||||
|
val senderMemberId: Long = SENDER_ID,
|
||||||
|
val status: GiftStatus = GiftStatus.RECEIVED,
|
||||||
|
val command: GiftTrackingRegistrationCommand = validGiftTrackingRegistrationCommand(),
|
||||||
|
val deliveryExists: Boolean = true
|
||||||
|
)
|
||||||
|
|
||||||
|
data class InvalidGiftRecipientAddressRegistrationScenario(
|
||||||
|
val requesterMemberId: Long = RECIPIENT_ID,
|
||||||
|
val recipientMemberId: Long = RECIPIENT_ID,
|
||||||
|
val status: GiftStatus = GiftStatus.TRACKING_REGISTERED,
|
||||||
|
val command: GiftRecipientAddressRegistrationCommand = validGiftRecipientAddressRegistrationCommand(),
|
||||||
|
val deliveryExists: Boolean = true
|
||||||
|
)
|
||||||
|
|
||||||
|
data class InvalidGiftDeliveryConfirmationScenario(
|
||||||
|
val requesterMemberId: Long = RECIPIENT_ID,
|
||||||
|
val recipientMemberId: Long = RECIPIENT_ID,
|
||||||
|
val status: GiftStatus = GiftStatus.INSPECTION_COMPLETED,
|
||||||
|
val deliveryExists: Boolean = true
|
||||||
|
)
|
||||||
|
|
||||||
|
data class InvalidGiftReviewScenario(
|
||||||
|
val requesterMemberId: Long = SENDER_ID,
|
||||||
|
val senderMemberId: Long = SENDER_ID,
|
||||||
|
val status: GiftStatus = GiftStatus.DELIVERED,
|
||||||
|
val command: GiftReviewCommand = validGiftReviewCommand(),
|
||||||
|
val reviewExists: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
const val MEMBER_ID = 1L
|
||||||
|
const val CHARGE_ID = 10L
|
||||||
|
const val USE_CAN_ID = 100L
|
||||||
|
const val INITIAL_CAN = 100
|
||||||
|
const val GIFT_PRICE_CAN = 30
|
||||||
|
const val SENDER_ID = 2L
|
||||||
|
const val OTHER_MEMBER_ID = 4L
|
||||||
|
const val RECIPIENT_ID = 3L
|
||||||
|
const val CATEGORY_ID = 4L
|
||||||
|
const val GIFT_ID = 5L
|
||||||
|
const val REVIEW_ID = 6L
|
||||||
|
const val APPLICATION_NO = "G20260929000001"
|
||||||
|
const val BASE_PRICE_CAN = 100
|
||||||
|
const val SALE_PRICE_CAN = 80
|
||||||
|
val NOW: LocalDateTime = LocalDateTime.of(2026, 9, 29, 12, 0)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun invalidGiftApplicationScenarios() = listOf(
|
||||||
|
InvalidGiftApplicationScenario(validGiftApplicationCommand().copy(senderName = "")),
|
||||||
|
InvalidGiftApplicationScenario(validGiftApplicationCommand().copy(senderPhoneNumber = "")),
|
||||||
|
InvalidGiftApplicationScenario(validGiftApplicationCommand().copy(senderZipCode = "")),
|
||||||
|
InvalidGiftApplicationScenario(validGiftApplicationCommand().copy(senderAddress = "")),
|
||||||
|
InvalidGiftApplicationScenario(validGiftApplicationCommand().copy(senderTermsAgreed = false)),
|
||||||
|
InvalidGiftApplicationScenario(validGiftApplicationCommand().copy(senderPrivacyAgreed = false)),
|
||||||
|
InvalidGiftApplicationScenario(validGiftApplicationCommand(), categoryActive = false),
|
||||||
|
InvalidGiftApplicationScenario(
|
||||||
|
validGiftApplicationCommand().copy(damageWaiverAgreed = false),
|
||||||
|
requiresDamageWaiver = true
|
||||||
|
),
|
||||||
|
InvalidGiftApplicationScenario(validGiftApplicationCommand(), sizePriceActive = false),
|
||||||
|
InvalidGiftApplicationScenario(validGiftApplicationCommand(), creatorExists = false)
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun invalidGiftCancellationScenarios() = listOf(
|
||||||
|
InvalidGiftCancellationScenario(OTHER_MEMBER_ID, SENDER_ID, GiftStatus.RECEIVED),
|
||||||
|
InvalidGiftCancellationScenario(SENDER_ID, SENDER_ID, GiftStatus.TRACKING_REGISTERED)
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun invalidGiftTrackingRegistrationScenarios() = listOf(
|
||||||
|
InvalidGiftTrackingRegistrationScenario(requesterMemberId = OTHER_MEMBER_ID),
|
||||||
|
InvalidGiftTrackingRegistrationScenario(status = GiftStatus.TRACKING_REGISTERED),
|
||||||
|
InvalidGiftTrackingRegistrationScenario(
|
||||||
|
command = validGiftTrackingRegistrationCommand().copy(courierCompanyName = "")
|
||||||
|
),
|
||||||
|
InvalidGiftTrackingRegistrationScenario(
|
||||||
|
command = validGiftTrackingRegistrationCommand().copy(courierCompanyName = "a".repeat(51))
|
||||||
|
),
|
||||||
|
InvalidGiftTrackingRegistrationScenario(
|
||||||
|
command = validGiftTrackingRegistrationCommand().copy(trackingNumber = "")
|
||||||
|
),
|
||||||
|
InvalidGiftTrackingRegistrationScenario(deliveryExists = false)
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun recipientAddressRegistrableStatuses() = listOf(
|
||||||
|
GiftStatus.TRACKING_REGISTERED,
|
||||||
|
GiftStatus.ARRIVED_AT_MAILBOX,
|
||||||
|
GiftStatus.INSPECTION_COMPLETED
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun invalidGiftRecipientAddressRegistrationScenarios() = listOf(
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(requesterMemberId = OTHER_MEMBER_ID),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(status = GiftStatus.RECEIVED),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(status = GiftStatus.DELIVERED),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(status = GiftStatus.UNDELIVERABLE),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(status = GiftStatus.CANCELED),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(
|
||||||
|
command = validGiftRecipientAddressRegistrationCommand().copy(name = "")
|
||||||
|
),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(
|
||||||
|
command = validGiftRecipientAddressRegistrationCommand().copy(phoneNumber = "")
|
||||||
|
),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(
|
||||||
|
command = validGiftRecipientAddressRegistrationCommand().copy(zipCode = "")
|
||||||
|
),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(
|
||||||
|
command = validGiftRecipientAddressRegistrationCommand().copy(address = "")
|
||||||
|
),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(
|
||||||
|
command = validGiftRecipientAddressRegistrationCommand().copy(recipientTermsAgreed = false)
|
||||||
|
),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(
|
||||||
|
command = validGiftRecipientAddressRegistrationCommand().copy(recipientPrivacyAgreed = false)
|
||||||
|
),
|
||||||
|
InvalidGiftRecipientAddressRegistrationScenario(deliveryExists = false)
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun invalidGiftDeliveryConfirmationScenarios() = listOf(
|
||||||
|
InvalidGiftDeliveryConfirmationScenario(requesterMemberId = OTHER_MEMBER_ID),
|
||||||
|
InvalidGiftDeliveryConfirmationScenario(status = GiftStatus.TRACKING_REGISTERED),
|
||||||
|
InvalidGiftDeliveryConfirmationScenario(status = GiftStatus.DELIVERED),
|
||||||
|
InvalidGiftDeliveryConfirmationScenario(deliveryExists = false)
|
||||||
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun invalidGiftReviewScenarios() = listOf(
|
||||||
|
InvalidGiftReviewScenario(requesterMemberId = OTHER_MEMBER_ID),
|
||||||
|
InvalidGiftReviewScenario(status = GiftStatus.INSPECTION_COMPLETED),
|
||||||
|
InvalidGiftReviewScenario(reviewExists = true),
|
||||||
|
InvalidGiftReviewScenario(command = validGiftReviewCommand().copy(rating = 0)),
|
||||||
|
InvalidGiftReviewScenario(command = validGiftReviewCommand().copy(rating = 6)),
|
||||||
|
InvalidGiftReviewScenario(command = validGiftReviewCommand().copy(keywords = listOf("a".repeat(256)))),
|
||||||
|
InvalidGiftReviewScenario(command = validGiftReviewCommand().copy(comment = "a".repeat(256)))
|
||||||
|
)
|
||||||
|
|
||||||
|
fun validGiftApplicationCommand() = GiftApplicationCommand(
|
||||||
|
recipientMemberId = RECIPIENT_ID,
|
||||||
|
senderName = "홍길동",
|
||||||
|
senderPhoneNumber = "01012345678",
|
||||||
|
senderZipCode = "06234",
|
||||||
|
senderAddress = "서울시 강남구",
|
||||||
|
senderAddressDetail = "101동 1001호",
|
||||||
|
sizeCode = GiftSize.SMALL,
|
||||||
|
categoryId = CATEGORY_ID,
|
||||||
|
senderTermsAgreed = true,
|
||||||
|
senderPrivacyAgreed = true,
|
||||||
|
damageWaiverAgreed = true
|
||||||
|
)
|
||||||
|
|
||||||
|
fun validGiftTrackingRegistrationCommand() = GiftTrackingRegistrationCommand(
|
||||||
|
courierCompanyName = "CJ대한통운",
|
||||||
|
trackingNumber = "1234567890"
|
||||||
|
)
|
||||||
|
|
||||||
|
fun validGiftRecipientAddressRegistrationCommand() = GiftRecipientAddressRegistrationCommand(
|
||||||
|
name = "김소다",
|
||||||
|
phoneNumber = "01098765432",
|
||||||
|
zipCode = "04524",
|
||||||
|
address = "서울시 중구",
|
||||||
|
addressDetail = "202호",
|
||||||
|
recipientTermsAgreed = true,
|
||||||
|
recipientPrivacyAgreed = true
|
||||||
|
)
|
||||||
|
|
||||||
|
fun validGiftReviewCommand() = GiftReviewCommand(
|
||||||
|
rating = 5,
|
||||||
|
keywords = listOf("배송이 빨라요", "안내가 친절해요"),
|
||||||
|
comment = "선물 전달 과정이 만족스러웠습니다."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user