diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateController.kt index 30dbe37..ddcb051 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateController.kt @@ -48,4 +48,46 @@ class AdminCalculateController(private val service: AdminCalculateService) { pageable.pageSize.toLong() ) ) + + @GetMapping("/live-by-creator") + fun getCalculateLiveByCreator( + @RequestParam startDateStr: String, + @RequestParam endDateStr: String, + pageable: Pageable + ) = ApiResponse.ok( + service.getCalculateLiveByCreator( + startDateStr, + endDateStr, + pageable.offset, + pageable.pageSize.toLong() + ) + ) + + @GetMapping("/content-by-creator") + fun getCalculateContentByCreator( + @RequestParam startDateStr: String, + @RequestParam endDateStr: String, + pageable: Pageable + ) = ApiResponse.ok( + service.getCalculateContentByCreator( + startDateStr, + endDateStr, + pageable.offset, + pageable.pageSize.toLong() + ) + ) + + @GetMapping("/community-by-creator") + fun getCalculateCommunityByCreator( + @RequestParam startDateStr: String, + @RequestParam endDateStr: String, + pageable: Pageable + ) = ApiResponse.ok( + service.getCalculateCommunityByCreator( + startDateStr, + endDateStr, + pageable.offset, + pageable.pageSize.toLong() + ) + ) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateQueryRepository.kt index a4d25f3..6a45e4a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateQueryRepository.kt @@ -224,4 +224,156 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { .limit(limit) .fetch() } + + fun getCalculateLiveByCreatorTotalCount(startDate: LocalDateTime, endDate: LocalDateTime): Int { + return queryFactory + .select(member.id) + .from(useCan) + .innerJoin(useCan.room, liveRoom) + .innerJoin(liveRoom.member, member) + .leftJoin(creatorSettlementRatio) + .on(member.id.eq(creatorSettlementRatio.member.id)) + .where( + useCan.isRefund.isFalse + .and(useCan.createdAt.goe(startDate)) + .and(useCan.createdAt.loe(endDate)) + ) + .groupBy(member.id) + .fetch() + .size + } + + fun getCalculateLiveByCreator( + startDate: LocalDateTime, + endDate: LocalDateTime, + offset: Long, + limit: Long + ): List { + return queryFactory + .select( + QGetCalculateByCreatorQueryData( + member.email, + member.nickname, + useCan.can.add(useCan.rewardCan).sum(), + creatorSettlementRatio.liveSettlementRatio + ) + ) + .from(useCan) + .innerJoin(useCan.room, liveRoom) + .innerJoin(liveRoom.member, member) + .leftJoin(creatorSettlementRatio) + .on(member.id.eq(creatorSettlementRatio.member.id)) + .where( + useCan.isRefund.isFalse + .and(useCan.createdAt.goe(startDate)) + .and(useCan.createdAt.loe(endDate)) + ) + .groupBy(member.id, creatorSettlementRatio.liveSettlementRatio) + .orderBy(member.id.desc()) + .offset(offset) + .limit(limit) + .fetch() + } + + fun getCalculateContentByCreatorTotalCount(startDate: LocalDateTime, endDate: LocalDateTime): Int { + return queryFactory + .select(member.id) + .from(order) + .innerJoin(order.audioContent, audioContent) + .innerJoin(audioContent.member, member) + .leftJoin(creatorSettlementRatio) + .on(member.id.eq(creatorSettlementRatio.member.id)) + .where( + order.createdAt.goe(startDate) + .and(order.createdAt.loe(endDate)) + .and(order.isActive.isTrue) + ) + .groupBy(member.id) + .fetch() + .size + } + + fun getCalculateContentByCreator( + startDate: LocalDateTime, + endDate: LocalDateTime, + offset: Long, + limit: Long + ): List { + return queryFactory + .select( + QGetCalculateByCreatorQueryData( + member.email, + member.nickname, + order.can.sum(), + creatorSettlementRatio.contentSettlementRatio + ) + ) + .from(order) + .innerJoin(order.audioContent, audioContent) + .innerJoin(audioContent.member, member) + .leftJoin(creatorSettlementRatio) + .on(member.id.eq(creatorSettlementRatio.member.id)) + .where( + order.createdAt.goe(startDate) + .and(order.createdAt.loe(endDate)) + .and(order.isActive.isTrue) + ) + .groupBy(member.id) + .orderBy(member.id.desc()) + .offset(offset) + .limit(limit) + .fetch() + } + + fun getCalculateCommunityByCreatorTotalCount(startDate: LocalDateTime, endDate: LocalDateTime): Int { + return queryFactory + .select(member.id) + .from(useCan) + .innerJoin(useCan.communityPost, creatorCommunity) + .innerJoin(creatorCommunity.member, member) + .leftJoin(creatorSettlementRatio) + .on(member.id.eq(creatorSettlementRatio.member.id)) + .where( + useCan.isRefund.isFalse + .and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST)) + .and(useCan.createdAt.goe(startDate)) + .and(useCan.createdAt.loe(endDate)) + ) + .groupBy(member.id) + .fetch() + .size + } + + fun getCalculateCommunityByCreator( + startDate: LocalDateTime, + endDate: LocalDateTime, + offset: Long, + limit: Long + ): List { + return queryFactory + .select( + QGetCalculateByCreatorQueryData( + member.email, + member.nickname, + useCan.can.add(useCan.rewardCan).sum(), + creatorSettlementRatio.communitySettlementRatio + ) + ) + .from(useCan) + .innerJoin(useCan.communityPost, creatorCommunity) + .innerJoin(creatorCommunity.member, member) + .leftJoin(creatorSettlementRatio) + .on(member.id.eq(creatorSettlementRatio.member.id)) + .where( + useCan.isRefund.isFalse + .and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST)) + .and(useCan.createdAt.goe(startDate)) + .and(useCan.createdAt.loe(endDate)) + ) + .groupBy(member.id, creatorSettlementRatio.communitySettlementRatio) + .orderBy(member.id.desc()) + .offset(offset) + .limit(limit) + .fetch() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateService.kt index f82afed..255d456 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateService.kt @@ -10,7 +10,7 @@ import org.springframework.transaction.annotation.Transactional class AdminCalculateService(private val repository: AdminCalculateQueryRepository) { @Transactional(readOnly = true) @Cacheable( - cacheNames = ["default"], + cacheNames = ["cache_ttl_3_hours"], key = "'calculateLive:' + " + "#startDateStr + ':' + #endDateStr" ) fun getCalculateLive(startDateStr: String, endDateStr: String): List { @@ -67,6 +67,11 @@ class AdminCalculateService(private val repository: AdminCalculateQueryRepositor .map { it.toGetCalculateContentDonationResponse() } } + @Transactional(readOnly = true) + @Cacheable( + cacheNames = ["cache_ttl_3_hours"], + key = "'calculateCommunityPost:' + " + "#startDateStr + ':' + #endDateStr + ':' + #offset" + ) fun getCalculateCommunityPost( startDateStr: String, endDateStr: String, @@ -83,4 +88,55 @@ class AdminCalculateService(private val repository: AdminCalculateQueryRepositor return GetCreatorCalculateCommunityPostResponse(totalCount, items) } + + fun getCalculateLiveByCreator( + startDateStr: String, + endDateStr: String, + offset: Long, + limit: Long + ) = run { + val startDate = startDateStr.convertLocalDateTime() + val endDate = endDateStr.convertLocalDateTime(hour = 23, minute = 59, second = 59) + + val totalCount = repository.getCalculateLiveByCreatorTotalCount(startDate, endDate) + val items = repository + .getCalculateLiveByCreator(startDate, endDate, offset, limit) + .map { it.toGetCalculateByCreator() } + + GetCalculateByCreatorResponse(totalCount, items) + } + + fun getCalculateContentByCreator( + startDateStr: String, + endDateStr: String, + offset: Long, + limit: Long + ) = run { + val startDate = startDateStr.convertLocalDateTime() + val endDate = endDateStr.convertLocalDateTime(hour = 23, minute = 59, second = 59) + + val totalCount = repository.getCalculateContentByCreatorTotalCount(startDate, endDate) + val items = repository + .getCalculateContentByCreator(startDate, endDate, offset, limit) + .map { it.toGetCalculateByCreator() } + + GetCalculateByCreatorResponse(totalCount, items) + } + + fun getCalculateCommunityByCreator( + startDateStr: String, + endDateStr: String, + offset: Long, + limit: Long + ) = run { + val startDate = startDateStr.convertLocalDateTime() + val endDate = endDateStr.convertLocalDateTime(hour = 23, minute = 59, second = 59) + + val totalCount = repository.getCalculateCommunityByCreatorTotalCount(startDate, endDate) + val items = repository + .getCalculateCommunityByCreator(startDate, endDate, offset, limit) + .map { it.toGetCalculateByCreator() } + + GetCalculateByCreatorResponse(totalCount, items) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateByCreatorItem.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateByCreatorItem.kt new file mode 100644 index 0000000..6b33b29 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateByCreatorItem.kt @@ -0,0 +1,14 @@ +package kr.co.vividnext.sodalive.admin.calculate + +import com.fasterxml.jackson.annotation.JsonProperty + +data class GetCalculateByCreatorItem( + @JsonProperty("email") val email: String, + @JsonProperty("nickname") val nickname: String, + @JsonProperty("totalCan") val totalCan: Int, + @JsonProperty("totalKrw") val totalKrw: Int, + @JsonProperty("paymentFee") val paymentFee: Int, + @JsonProperty("settlementAmount") val settlementAmount: Int, + @JsonProperty("tax") val tax: Int, + @JsonProperty("depositAmount") val depositAmount: Int +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateByCreatorQueryData.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateByCreatorQueryData.kt new file mode 100644 index 0000000..e392da5 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateByCreatorQueryData.kt @@ -0,0 +1,44 @@ +package kr.co.vividnext.sodalive.admin.calculate + +import com.querydsl.core.annotations.QueryProjection +import java.math.BigDecimal +import java.math.RoundingMode + +data class GetCalculateByCreatorQueryData @QueryProjection constructor( + val email: String, + val nickname: String, + val totalCan: Int, + val settlementRatio: Int? +) { + fun toGetCalculateByCreator(): GetCalculateByCreatorItem { + // 원화 = totalCoin * 100 ( 캔 1개 = 100원 ) + val totalKrw = BigDecimal(totalCan).multiply(BigDecimal(100)) + + // 결제수수료 : 6.6% + val paymentFee = totalKrw.multiply(BigDecimal(0.066)) + + // 정산금액 = (원화 - 결제수수료) 의 70% + val settlementAmount = if (settlementRatio != null) { + totalKrw.subtract(paymentFee).multiply(BigDecimal(settlementRatio).divide(BigDecimal(100.0))) + } else { + totalKrw.subtract(paymentFee).multiply(BigDecimal(0.7)) + } + + // 원천세 = 정산금액의 3.3% + val tax = settlementAmount.multiply(BigDecimal(0.033)) + + // 입금액 + val depositAmount = settlementAmount.subtract(tax) + + return GetCalculateByCreatorItem( + email = email, + nickname = nickname, + totalCan = totalCan, + totalKrw = totalKrw.toInt(), + paymentFee = paymentFee.setScale(0, RoundingMode.HALF_UP).toInt(), + settlementAmount = settlementAmount.setScale(0, RoundingMode.HALF_UP).toInt(), + tax = tax.setScale(0, RoundingMode.HALF_UP).toInt(), + depositAmount = depositAmount.setScale(0, RoundingMode.HALF_UP).toInt() + ) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateByCreatorResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateByCreatorResponse.kt new file mode 100644 index 0000000..49036e3 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateByCreatorResponse.kt @@ -0,0 +1,6 @@ +package kr.co.vividnext.sodalive.admin.calculate + +data class GetCalculateByCreatorResponse( + val totalCount: Int, + val items: List +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/CanRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/CanRepository.kt index 418d9fb..61863a0 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/CanRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/CanRepository.kt @@ -109,6 +109,7 @@ class CanQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CanQue member.id.eq(memberId) .and(liveRoom.id.eq(roomId)) .and(useCan.canUsage.eq(CanUsage.LIVE)) + .and(useCan.isRefund.isFalse) ) .orderBy(useCan.id.desc()) .fetchFirst() diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/roulette/v2/RouletteService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/roulette/v2/RouletteService.kt index b8c39e9..6529381 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/roulette/v2/RouletteService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/roulette/v2/RouletteService.kt @@ -237,7 +237,7 @@ class RouletteService( } val totalPercentage = items.map { it.percentage }.sum() - if (totalPercentage != 100f) { + if (totalPercentage > 100.1f || totalPercentage <= 99.99f) { throw SodaException("확률이 100%가 아닙니다") } }