test #152
|
@ -82,6 +82,8 @@ class AdminAudioContentQueryRepositoryImpl(
|
|||
audioContentTheme.theme,
|
||||
audioContentTheme.id,
|
||||
audioContent.price,
|
||||
audioContent.limited,
|
||||
audioContent.remaining,
|
||||
audioContent.isAdult,
|
||||
audioContent.duration,
|
||||
audioContent.content,
|
||||
|
|
|
@ -18,6 +18,8 @@ data class GetAdminContentListItem @QueryProjection constructor(
|
|||
val theme: String,
|
||||
val themeId: Long,
|
||||
val price: Int,
|
||||
val totalContentCount: Int?,
|
||||
val remainingContentCount: Int?,
|
||||
val isAdult: Boolean,
|
||||
val remainingTime: String,
|
||||
var contentUrl: String,
|
||||
|
|
|
@ -34,6 +34,8 @@ data class AudioContent(
|
|||
var detail: String,
|
||||
val price: Int = 0,
|
||||
var releaseDate: LocalDateTime? = null,
|
||||
val limited: Int? = null,
|
||||
var remaining: Int? = null,
|
||||
@Enumerated(value = EnumType.STRING)
|
||||
val type: AudioContentType = AudioContentType.INDIVIDUAL,
|
||||
val isGeneratePreview: Boolean = true,
|
||||
|
|
|
@ -14,6 +14,7 @@ import kr.co.vividnext.sodalive.content.like.AudioContentLikeRepository
|
|||
import kr.co.vividnext.sodalive.content.like.PutAudioContentLikeRequest
|
||||
import kr.co.vividnext.sodalive.content.like.PutAudioContentLikeResponse
|
||||
import kr.co.vividnext.sodalive.content.main.GetAudioContentRanking
|
||||
import kr.co.vividnext.sodalive.content.order.LimitedEditionOrderRepository
|
||||
import kr.co.vividnext.sodalive.content.order.OrderRepository
|
||||
import kr.co.vividnext.sodalive.content.order.OrderType
|
||||
import kr.co.vividnext.sodalive.content.pin.PinContent
|
||||
|
@ -47,6 +48,7 @@ class AudioContentService(
|
|||
private val blockMemberRepository: BlockMemberRepository,
|
||||
private val hashTagRepository: HashTagRepository,
|
||||
private val orderRepository: OrderRepository,
|
||||
private val limitedEditionOrderRepository: LimitedEditionOrderRepository,
|
||||
private val themeQueryRepository: AudioContentThemeQueryRepository,
|
||||
private val playbackTrackingRepository: PlaybackTrackingRepository,
|
||||
private val commentRepository: AudioContentCommentRepository,
|
||||
|
@ -183,13 +185,15 @@ class AudioContentService(
|
|||
0
|
||||
},
|
||||
releaseDate = releaseDate,
|
||||
limited = request.limited,
|
||||
remaining = request.limited,
|
||||
isAdult = request.isAdult,
|
||||
isGeneratePreview = if (request.type == AudioContentType.INDIVIDUAL) {
|
||||
request.isGeneratePreview
|
||||
} else {
|
||||
false
|
||||
},
|
||||
isOnlyRental = request.isOnlyRental,
|
||||
isOnlyRental = if (request.limited != null && request.limited > 0) false else request.isOnlyRental,
|
||||
isCommentAvailable = request.isCommentAvailable
|
||||
)
|
||||
audioContent.theme = theme
|
||||
|
@ -463,11 +467,21 @@ class AudioContentService(
|
|||
contentId = audioContent.id!!
|
||||
)
|
||||
|
||||
val existOrdered = isExistsBundleAudioContent || isExistsAudioContent
|
||||
val orderSequence = if (existOrdered) {
|
||||
limitedEditionOrderRepository.getOrderSequence(
|
||||
contentId = audioContent.id!!,
|
||||
memberId = member.id!!
|
||||
)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
|
||||
if (
|
||||
!isExistsAudioContent &&
|
||||
!isExistsBundleAudioContent &&
|
||||
!existOrdered &&
|
||||
!audioContent.isActive &&
|
||||
audioContent.releaseDate == null
|
||||
audioContent.releaseDate != null &&
|
||||
audioContent.releaseDate!! < LocalDateTime.now()
|
||||
) {
|
||||
throw SodaException("잘못된 콘텐츠 입니다.\n다시 시도해 주세요.")
|
||||
}
|
||||
|
@ -591,11 +605,14 @@ class AudioContentService(
|
|||
price = audioContent.price,
|
||||
duration = audioContent.duration ?: "",
|
||||
releaseDate = releaseDate,
|
||||
totalContentCount = audioContent.limited,
|
||||
remainingContentCount = audioContent.remaining,
|
||||
orderSequence = orderSequence,
|
||||
isActivePreview = audioContent.isGeneratePreview,
|
||||
isAdult = audioContent.isAdult,
|
||||
isMosaic = audioContent.isAdult && member.auth == null,
|
||||
isOnlyRental = audioContent.isOnlyRental,
|
||||
existOrdered = isExistsBundleAudioContent || isExistsAudioContent,
|
||||
existOrdered = existOrdered,
|
||||
orderType = orderType,
|
||||
remainingTime = remainingTime,
|
||||
creatorOtherContentList = creatorOtherContentList,
|
||||
|
|
|
@ -5,6 +5,7 @@ data class CreateAudioContentRequest(
|
|||
val detail: String,
|
||||
val tags: String,
|
||||
val price: Int,
|
||||
val limited: Int? = null,
|
||||
val timezone: String = "Asia/Seoul",
|
||||
val releaseDate: String? = null,
|
||||
val themeId: Long = 0,
|
||||
|
|
|
@ -15,6 +15,9 @@ data class GetAudioContentDetailResponse(
|
|||
val price: Int,
|
||||
val duration: String,
|
||||
val releaseDate: String?,
|
||||
val totalContentCount: Int?,
|
||||
val remainingContentCount: Int?,
|
||||
val orderSequence: Int?,
|
||||
val isActivePreview: Boolean,
|
||||
val isAdult: Boolean,
|
||||
val isMosaic: Boolean,
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package kr.co.vividnext.sodalive.content.order
|
||||
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||
import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
|
||||
import kr.co.vividnext.sodalive.content.order.QLimitedEditionOrder.limitedEditionOrder
|
||||
import kr.co.vividnext.sodalive.content.order.QOrder.order
|
||||
import kr.co.vividnext.sodalive.member.QMember.member
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
interface LimitedEditionOrderRepository : JpaRepository<LimitedEditionOrder, Long>, LimitedEditionOrderQueryRepository
|
||||
|
||||
interface LimitedEditionOrderQueryRepository {
|
||||
fun getNextSequence(contentId: Long): Int
|
||||
|
||||
fun getOrderSequence(contentId: Long, memberId: Long): Int?
|
||||
}
|
||||
|
||||
class LimitedEditionOrderQueryRepositoryImpl(
|
||||
private val queryFactory: JPAQueryFactory
|
||||
) : LimitedEditionOrderQueryRepository {
|
||||
override fun getNextSequence(contentId: Long): Int {
|
||||
val maxSequence = queryFactory.select(limitedEditionOrder.sequence)
|
||||
.from(limitedEditionOrder)
|
||||
.innerJoin(limitedEditionOrder.audioContent, audioContent)
|
||||
.where(limitedEditionOrder.audioContent.id.eq(contentId))
|
||||
.orderBy(limitedEditionOrder.sequence.desc())
|
||||
.limit(1)
|
||||
.fetchFirst()
|
||||
|
||||
return if (maxSequence == null) {
|
||||
1
|
||||
} else {
|
||||
maxSequence + 1
|
||||
}
|
||||
}
|
||||
|
||||
override fun getOrderSequence(contentId: Long, memberId: Long): Int? {
|
||||
return queryFactory.select(limitedEditionOrder.sequence)
|
||||
.from(limitedEditionOrder)
|
||||
.innerJoin(limitedEditionOrder.audioContent, audioContent)
|
||||
.innerJoin(limitedEditionOrder.order, order)
|
||||
.innerJoin(order.member, member)
|
||||
.where(
|
||||
limitedEditionOrder.audioContent.id.eq(contentId)
|
||||
.and(limitedEditionOrder.order.member.id.eq(memberId))
|
||||
)
|
||||
.fetchFirst()
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -81,6 +81,8 @@ class CreatorAdminAudioContentQueryRepositoryImpl(
|
|||
audioContent.member!!.nickname,
|
||||
audioContentTheme.theme,
|
||||
audioContent.price,
|
||||
audioContent.limited,
|
||||
audioContent.remaining,
|
||||
audioContent.isAdult,
|
||||
audioContent.isCommentAvailable,
|
||||
audioContent.duration,
|
||||
|
|
|
@ -15,6 +15,8 @@ data class GetCreatorAdminContentListItem @QueryProjection constructor(
|
|||
val creatorNickname: String,
|
||||
val theme: String,
|
||||
val price: Int,
|
||||
val totalContentCount: Int?,
|
||||
val remainingContentCount: Int?,
|
||||
val isAdult: Boolean,
|
||||
val isCommentAvailable: Boolean,
|
||||
val remainingTime: String,
|
||||
|
|
Loading…
Reference in New Issue