diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateController.kt index 409c472..50235ff 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateController.kt @@ -53,4 +53,23 @@ class CreatorAdminCalculateController(private val service: CreatorAdminCalculate ApiResponse.ok(service.getCumulativeSalesByContent(member.id!!, pageable.offset, pageable.pageSize.toLong())) } + + @GetMapping("/content-donation-list") + fun getCalculateContentDonationList( + @RequestParam startDateStr: String, + @RequestParam endDateStr: String, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, + pageable: Pageable + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + ApiResponse.ok( + service.getCalculateContentDonationList( + startDateStr, + endDateStr, + member.id!!, + pageable.offset, + pageable.pageSize.toLong() + ) + ) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateQueryRepository.kt index 8616741..c3c22c7 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateQueryRepository.kt @@ -4,12 +4,15 @@ import com.querydsl.core.types.dsl.DateTimePath import com.querydsl.core.types.dsl.Expressions import com.querydsl.core.types.dsl.StringTemplate import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.admin.calculate.GetCalculateContentDonationQueryData import kr.co.vividnext.sodalive.admin.calculate.GetCalculateContentQueryData import kr.co.vividnext.sodalive.admin.calculate.GetCalculateLiveQueryData import kr.co.vividnext.sodalive.admin.calculate.GetCumulativeSalesByContentQueryData +import kr.co.vividnext.sodalive.admin.calculate.QGetCalculateContentDonationQueryData import kr.co.vividnext.sodalive.admin.calculate.QGetCalculateContentQueryData import kr.co.vividnext.sodalive.admin.calculate.QGetCalculateLiveQueryData import kr.co.vividnext.sodalive.admin.calculate.QGetCumulativeSalesByContentQueryData +import kr.co.vividnext.sodalive.can.use.CanUsage import kr.co.vividnext.sodalive.can.use.QUseCan.useCan import kr.co.vividnext.sodalive.can.use.QUseCanCalculate.useCanCalculate import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus @@ -184,4 +187,63 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac .orderBy(member.id.desc(), audioContent.id.desc()) .fetch() } + + fun getCalculateContentDonationListTotalCount( + startDate: LocalDateTime, + endDate: LocalDateTime, + memberId: Long + ): Int { + val donationFormattedDate = getFormattedDate(useCan.createdAt) + return queryFactory + .select(audioContent.id) + .from(useCan) + .innerJoin(useCan.audioContent, audioContent) + .innerJoin(audioContent.member, member) + .where( + useCan.isRefund.isFalse + .and(useCan.canUsage.eq(CanUsage.DONATION)) + .and(useCan.createdAt.goe(startDate)) + .and(useCan.createdAt.loe(endDate)) + .and(audioContent.member.id.eq(memberId)) + ) + .groupBy(donationFormattedDate, audioContent.id) + .fetch() + .size + } + + fun getCalculateContentDonationList( + startDate: LocalDateTime, + endDate: LocalDateTime, + memberId: Long, + offset: Long, + limit: Long + ): List { + val donationFormattedDate = getFormattedDate(useCan.createdAt) + return queryFactory + .select( + QGetCalculateContentDonationQueryData( + member.nickname, + audioContent.title, + getFormattedDate(audioContent.createdAt), + donationFormattedDate, + useCan.id.count(), + useCan.can.add(useCan.rewardCan).sum() + ) + ) + .from(useCan) + .innerJoin(useCan.audioContent, audioContent) + .innerJoin(audioContent.member, member) + .where( + useCan.isRefund.isFalse + .and(useCan.canUsage.eq(CanUsage.DONATION)) + .and(useCan.createdAt.goe(startDate)) + .and(useCan.createdAt.loe(endDate)) + .and(audioContent.member.id.eq(memberId)) + ) + .groupBy(donationFormattedDate, audioContent.id) + .offset(offset) + .limit(limit) + .orderBy(member.id.asc(), donationFormattedDate.desc()) + .fetch() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateService.kt index 4cec361..c55931f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateService.kt @@ -1,6 +1,7 @@ package kr.co.vividnext.sodalive.creator.admin.calculate import kr.co.vividnext.sodalive.admin.calculate.CumulativeSalesByContentItem +import kr.co.vividnext.sodalive.admin.calculate.GetCalculateContentDonationResponse import kr.co.vividnext.sodalive.admin.calculate.GetCalculateContentResponse import kr.co.vividnext.sodalive.admin.calculate.GetCalculateLiveResponse import kr.co.vividnext.sodalive.admin.calculate.GetCumulativeSalesByContentResponse @@ -205,4 +206,67 @@ class CreatorAdminCalculateService(private val repository: CreatorAdminCalculate return GetCumulativeSalesByContentResponse(totalCount, items) } + + @Transactional(readOnly = true) + @Cacheable( + cacheNames = ["cache_ttl_3_hours"], + key = "'creatorCalculateContentDonationList:' + " + + "#startDateStr + ':' + #endDateStr + ':' + #memberId + ':' + #offset + ':' + #limit" + ) + fun getCalculateContentDonationList( + startDateStr: String, + endDateStr: String, + memberId: Long, + offset: Long, + limit: Long + ): GetCreatorCalculateContentDonationResponse { + val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + val startDate = LocalDate.parse(startDateStr, dateTimeFormatter).atTime(0, 0, 0) + .atZone(ZoneId.of("Asia/Seoul")) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + + val endDate = LocalDate.parse(endDateStr, dateTimeFormatter).atTime(23, 59, 59) + .atZone(ZoneId.of("Asia/Seoul")) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + + val totalCount = repository.getCalculateContentDonationListTotalCount(startDate, endDate, memberId) + val items = repository + .getCalculateContentDonationList(startDate, endDate, memberId, offset, limit) + .asSequence() + .map { + // 원화 = totalCoin * 100 ( 캔 1개 = 100원 ) + val totalKrw = it.totalCan * 100 + + // 결제수수료 : 6.6% + val paymentFee = totalKrw * 0.066f + + // 정산금액 = (원화 - 결제수수료) 의 70% + val settlementAmount = (totalKrw.toFloat() - paymentFee) * 0.7 + + // 원천세 = 정산금액의 3.3% + val tax = settlementAmount * 0.033 + + // 입금액 + val depositAmount = settlementAmount - tax + + GetCalculateContentDonationResponse( + nickname = it.nickname, + title = it.title, + registrationDate = it.registrationDate, + donationDate = it.donationDate, + numberOfDonation = it.numberOfDonation.toInt(), + totalCan = it.totalCan, + totalKrw = totalKrw, + paymentFee = paymentFee.roundToInt(), + settlementAmount = settlementAmount.roundToInt(), + tax = tax.roundToInt(), + depositAmount = depositAmount.roundToInt() + ) + } + .toList() + + return GetCreatorCalculateContentDonationResponse(totalCount, items) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/GetCreatorCalculateContentDonationResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/GetCreatorCalculateContentDonationResponse.kt new file mode 100644 index 0000000..bde83a9 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/GetCreatorCalculateContentDonationResponse.kt @@ -0,0 +1,9 @@ +package kr.co.vividnext.sodalive.creator.admin.calculate + +import com.fasterxml.jackson.annotation.JsonProperty +import kr.co.vividnext.sodalive.admin.calculate.GetCalculateContentDonationResponse + +data class GetCreatorCalculateContentDonationResponse( + @JsonProperty("totalCount") val totalCount: Int, + @JsonProperty("items") val items: List +)