From 2d1f33309575aff9e360229e84e17336223d46cb Mon Sep 17 00:00:00 2001 From: Klaus Date: Tue, 26 Mar 2024 17:44:26 +0900 Subject: [PATCH] =?UTF-8?q?=ED=95=9C=EC=A0=95=ED=8C=90=20=EC=BD=98?= =?UTF-8?q?=ED=85=90=EC=B8=A0=20=EC=A3=BC=EB=AC=B8=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/content/AudioContentService.kt | 2 +- .../content/order/LimitedEditionOrder.kt | 22 ++++++++ .../order/LimitedEditionOrderRepository.kt | 30 +++++++++++ .../sodalive/content/order/OrderService.kt | 54 ++++++++++++++----- 4 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/order/LimitedEditionOrder.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/order/LimitedEditionOrderRepository.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt index f62c88a..9a0ff30 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -191,7 +191,7 @@ class AudioContentService( } else { false }, - isOnlyRental = request.isOnlyRental, + isOnlyRental = if (request.limited != null && request.limited > 0) false else request.isOnlyRental, isCommentAvailable = request.isCommentAvailable ) audioContent.theme = theme diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/LimitedEditionOrder.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/LimitedEditionOrder.kt new file mode 100644 index 0000000..766f82c --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/LimitedEditionOrder.kt @@ -0,0 +1,22 @@ +package kr.co.vividnext.sodalive.content.order + +import kr.co.vividnext.sodalive.common.BaseEntity +import kr.co.vividnext.sodalive.content.AudioContent +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.OneToOne + +@Entity +data class LimitedEditionOrder( + val sequence: Int +) : BaseEntity() { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "content_id", nullable = false) + var audioContent: AudioContent? = null + + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "order_id", nullable = false) + var order: Order? = null +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/LimitedEditionOrderRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/LimitedEditionOrderRepository.kt new file mode 100644 index 0000000..7e7c576 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/LimitedEditionOrderRepository.kt @@ -0,0 +1,30 @@ +package kr.co.vividnext.sodalive.content.order + +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.content.order.QLimitedEditionOrder.limitedEditionOrder +import org.springframework.data.jpa.repository.JpaRepository + +interface LimitedEditionOrderRepository : JpaRepository, LimitedEditionOrderQueryRepository + +interface LimitedEditionOrderQueryRepository { + fun getNextSequence(contentId: Long): Int +} + +class LimitedEditionOrderQueryRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : LimitedEditionOrderQueryRepository { + override fun getNextSequence(contentId: Long): Int { + val maxSequence = queryFactory.select(limitedEditionOrder.sequence) + .from(limitedEditionOrder) + .where(limitedEditionOrder.audioContent.id.eq(contentId)) + .orderBy(limitedEditionOrder.sequence.desc()) + .limit(1) + .fetchFirst() + + return if (maxSequence == null) { + 1 + } else { + maxSequence + 1 + } + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderService.kt index 0ca2b85..06cba52 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderService.kt @@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.content.order import kr.co.vividnext.sodalive.can.payment.CanPaymentService import kr.co.vividnext.sodalive.can.use.CanUsage import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.content.AudioContent import kr.co.vividnext.sodalive.content.AudioContentRepository import kr.co.vividnext.sodalive.content.comment.AudioContentCommentRepository import kr.co.vividnext.sodalive.content.like.AudioContentLikeRepository @@ -21,6 +22,7 @@ class OrderService( private val audioContentRepository: AudioContentRepository, private val audioContentCommentQueryRepository: AudioContentCommentRepository, private val audioContentLikeQueryRepository: AudioContentLikeRepository, + private val limitedEditionOrderRepository: LimitedEditionOrderRepository, @Value("\${cloud.aws.cloud-front.host}") private val audioContentCoverImageHost: String @@ -29,24 +31,15 @@ class OrderService( fun order(contentId: Long, orderType: OrderType, container: String, member: Member) { val content = audioContentRepository.findByIdAndActive(contentId) ?: throw SodaException("잘못된 콘텐츠 입니다\n다시 시도해 주세요.") + validateOrder(memberId = member.id!!, content = content) - val order = if (content.isOnlyRental) { - Order(type = OrderType.RENTAL) + val order = if (content.limited != null && content.remaining != null) { + if (content.remaining!! <= 0) throw SodaException("해당 콘텐츠가 매진되었습니다.") + orderLimitedEditionContent(content, member) } else { - Order(type = orderType) + orderContent(orderType, content, member) } - if (member.id!! == content.member!!.id!!) throw SodaException("자신이 올린 콘텐츠는 구매할 수 없습니다.") - if (repository.isExistOrdered(memberId = member.id!!, contentId = contentId)) { - throw SodaException("이미 구매한 콘텐츠 입니다.") - } - - order.member = member - order.creator = content.member - order.audioContent = content - - repository.save(order) - canPaymentService.spendCan( memberId = member.id!!, needCan = order.can, @@ -56,6 +49,39 @@ class OrderService( ) } + private fun orderContent(orderType: OrderType, content: AudioContent, member: Member): Order { + val order = if (content.isOnlyRental) { + Order(type = OrderType.RENTAL) + } else { + Order(type = orderType) + } + order.member = member + order.creator = content.member + order.audioContent = content + return repository.save(order) + } + + private fun orderLimitedEditionContent(content: AudioContent, member: Member): Order { + val order = orderContent(OrderType.KEEP, content, member) + + val sequence = limitedEditionOrderRepository.getNextSequence(content.id!!) + val limitedEditionOrder = LimitedEditionOrder(sequence = sequence) + limitedEditionOrder.order = order + limitedEditionOrder.audioContent = content + limitedEditionOrderRepository.save(limitedEditionOrder) + + content.remaining = content.remaining!! - 1 + + return order + } + + private fun validateOrder(memberId: Long, content: AudioContent) { + if (memberId == content.member!!.id!!) throw SodaException("자신이 올린 콘텐츠는 구매할 수 없습니다.") + if (repository.isExistOrdered(memberId = memberId, contentId = content.id!!)) { + throw SodaException("이미 구매한 콘텐츠 입니다.") + } + } + fun getAudioContentOrderList( member: Member, offset: Long,