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 4d8e7de3..3f203e70 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 @@ -86,6 +86,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { val pointGroup = CaseBuilder() .`when`(order.point.loe(0)).then(0) .otherwise(1) + val contentSettlementRatio = audioContent.settlementRatio.coalesce(creatorSettlementRatio.contentSettlementRatio) return queryFactory .select(audioContent.id) @@ -108,7 +109,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { orderFormattedDate, order.can, pointGroup, - creatorSettlementRatio.contentSettlementRatio + contentSettlementRatio ) .fetch() .size @@ -124,6 +125,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { val pointGroup = CaseBuilder() .`when`(order.point.loe(0)).then(0) .otherwise(1) + val contentSettlementRatio = audioContent.settlementRatio.coalesce(creatorSettlementRatio.contentSettlementRatio) return queryFactory .select( @@ -137,7 +139,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { order.id.count(), order.can.sum(), order.point.sum(), - creatorSettlementRatio.contentSettlementRatio + contentSettlementRatio ) ) .from(order) @@ -159,7 +161,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { orderFormattedDate, order.can, pointGroup, - creatorSettlementRatio.contentSettlementRatio + contentSettlementRatio ) .orderBy(member.id.desc(), orderFormattedDate.desc(), audioContent.id.asc()) .offset(offset) @@ -182,13 +184,23 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { } fun getCumulativeSalesByContentTotalCount(): Int { + val pointGroup = CaseBuilder() + .`when`(order.point.loe(0)).then(0) + .otherwise(1) + val contentSettlementRatio = audioContent.settlementRatio.coalesce(creatorSettlementRatio.contentSettlementRatio) + return queryFactory .select(audioContent.id) .from(order) .innerJoin(order.audioContent, audioContent) .innerJoin(audioContent.member, member) + .leftJoin(creatorSettlementRatio) + .on( + member.id.eq(creatorSettlementRatio.member.id) + .and(creatorSettlementRatio.deletedAt.isNull) + ) .where(order.isActive.isTrue) - .groupBy(member.id, audioContent.id, order.can) + .groupBy(member.id, audioContent.id, order.type, order.can, pointGroup, contentSettlementRatio) .fetch() .size } @@ -197,6 +209,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { val pointGroup = CaseBuilder() .`when`(order.point.loe(0)).then(0) .otherwise(1) + val contentSettlementRatio = audioContent.settlementRatio.coalesce(creatorSettlementRatio.contentSettlementRatio) return queryFactory .select( @@ -209,7 +222,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { order.id.count(), order.can.sum(), order.point.sum(), - creatorSettlementRatio.contentSettlementRatio + contentSettlementRatio ) ) .from(order) @@ -227,7 +240,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { order.type, order.can, pointGroup, - creatorSettlementRatio.contentSettlementRatio + contentSettlementRatio ) .offset(offset) .limit(limit) 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 eba2d596..0c782da1 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 @@ -74,18 +74,28 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac memberId: Long ): Int { val orderFormattedDate = getFormattedDate(order.createdAt) + val pointGroup = CaseBuilder() + .`when`(order.point.loe(0)).then(0) + .otherwise(1) + val contentSettlementRatio = audioContent.settlementRatio.coalesce(creatorSettlementRatio.contentSettlementRatio) + return queryFactory .select(audioContent.id) .from(order) .innerJoin(order.audioContent, audioContent) .innerJoin(audioContent.member, member) + .leftJoin(creatorSettlementRatio) + .on( + member.id.eq(creatorSettlementRatio.member.id) + .and(creatorSettlementRatio.deletedAt.isNull) + ) .where( order.createdAt.goe(startDate) .and(order.createdAt.loe(endDate)) .and(order.isActive.isTrue) .and(order.creator.id.eq(memberId)) ) - .groupBy(audioContent.id, order.type, orderFormattedDate, order.can) + .groupBy(audioContent.id, order.type, orderFormattedDate, order.can, pointGroup, contentSettlementRatio) .orderBy(member.id.desc(), orderFormattedDate.desc(), audioContent.id.asc()) .fetch() .size @@ -102,6 +112,7 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac val pointGroup = CaseBuilder() .`when`(order.point.loe(0)).then(0) .otherwise(1) + val contentSettlementRatio = audioContent.settlementRatio.coalesce(creatorSettlementRatio.contentSettlementRatio) return queryFactory .select( @@ -115,7 +126,7 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac order.id.count(), order.can.sum(), order.point.sum(), - creatorSettlementRatio.contentSettlementRatio + contentSettlementRatio ) ) .from(order) @@ -138,7 +149,7 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac orderFormattedDate, order.can, pointGroup, - creatorSettlementRatio.contentSettlementRatio + contentSettlementRatio ) .offset(offset) .limit(limit) @@ -161,16 +172,26 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac } fun getCumulativeSalesByContentTotalCount(memberId: Long): Int { + val pointGroup = CaseBuilder() + .`when`(order.point.loe(0)).then(0) + .otherwise(1) + val contentSettlementRatio = audioContent.settlementRatio.coalesce(creatorSettlementRatio.contentSettlementRatio) + return queryFactory .select(audioContent.id) .from(order) .innerJoin(order.audioContent, audioContent) .innerJoin(audioContent.member, member) + .leftJoin(creatorSettlementRatio) + .on( + member.id.eq(creatorSettlementRatio.member.id) + .and(creatorSettlementRatio.deletedAt.isNull) + ) .where( audioContent.member.id.eq(memberId) .and(order.isActive.isTrue) ) - .groupBy(member.id, audioContent.id, order.can) + .groupBy(member.id, audioContent.id, order.type, order.can, pointGroup, contentSettlementRatio) .fetch() .size } @@ -183,6 +204,7 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac val pointGroup = CaseBuilder() .`when`(order.point.loe(0)).then(0) .otherwise(1) + val contentSettlementRatio = audioContent.settlementRatio.coalesce(creatorSettlementRatio.contentSettlementRatio) return queryFactory .select( @@ -195,7 +217,7 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac order.id.count(), order.can.sum(), order.point.sum(), - creatorSettlementRatio.contentSettlementRatio + contentSettlementRatio ) ) .from(order) @@ -216,7 +238,7 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac order.type, order.can, pointGroup, - creatorSettlementRatio.contentSettlementRatio + contentSettlementRatio ) .offset(offset) .limit(limit) diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/admin/calculate/ContentSettlementCalculationTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/admin/calculate/ContentSettlementCalculationTest.kt new file mode 100644 index 00000000..75f095e7 --- /dev/null +++ b/src/test/kotlin/kr/co/vividnext/sodalive/admin/calculate/ContentSettlementCalculationTest.kt @@ -0,0 +1,102 @@ +package kr.co.vividnext.sodalive.admin.calculate + +import kr.co.vividnext.sodalive.content.order.OrderType +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.DisplayName +import org.junit.jupiter.api.Test + +class ContentSettlementCalculationTest { + @Test + @DisplayName("콘텐츠 정산 응답은 콘텐츠별 정산 요율을 우선 적용한다") + fun shouldApplyExplicitSettlementRatioForCalculateContentResponse() { + val result = GetCalculateContentQueryData( + nickname = "creator", + title = "content", + registrationDate = "2026-04-07", + saleDate = "2026-04-07", + orderType = OrderType.KEEP, + orderPrice = 100, + numberOfPeople = 2, + totalCan = 100, + totalPoint = 0, + settlementRatio = 80 + ).toGetCalculateContentResponse() + + assertEquals("소장", result.orderType) + assertEquals(10_000, result.totalKrw) + assertEquals(660, result.paymentFee) + assertEquals(7_472, result.settlementAmount) + assertEquals(247, result.tax) + assertEquals(7_225, result.depositAmount) + } + + @Test + @DisplayName("콘텐츠 정산 응답은 정산 요율이 없으면 70퍼센트 기본값으로 계산한다") + fun shouldFallbackToDefaultSettlementRatioForCalculateContentResponse() { + val result = GetCalculateContentQueryData( + nickname = "creator", + title = "content", + registrationDate = "2026-04-07", + saleDate = "2026-04-07", + orderType = OrderType.RENTAL, + orderPrice = 70, + numberOfPeople = 1, + totalCan = 100, + totalPoint = 0, + settlementRatio = null + ).toGetCalculateContentResponse() + + assertEquals("대여", result.orderType) + assertEquals(10_000, result.totalKrw) + assertEquals(660, result.paymentFee) + assertEquals(6_538, result.settlementAmount) + assertEquals(216, result.tax) + assertEquals(6_322, result.depositAmount) + } + + @Test + @DisplayName("누적 콘텐츠 정산 응답은 콘텐츠별 정산 요율을 우선 적용한다") + fun shouldApplyExplicitSettlementRatioForCumulativeSalesResponse() { + val result = GetCumulativeSalesByContentQueryData( + nickname = "creator", + title = "content", + registrationDate = "2026-04-07", + orderType = OrderType.KEEP, + orderPrice = 100, + numberOfPeople = 2, + totalCan = 100, + totalPoint = 0, + settlementRatio = 80 + ).toCumulativeSalesByContentItem() + + assertEquals("소장", result.orderType) + assertEquals(10_000, result.totalKrw) + assertEquals(660, result.paymentFee) + assertEquals(7_472, result.settlementAmount) + assertEquals(247, result.tax) + assertEquals(7_225, result.depositAmount) + } + + @Test + @DisplayName("누적 콘텐츠 정산 응답은 정산 요율이 없으면 70퍼센트 기본값으로 계산한다") + fun shouldFallbackToDefaultSettlementRatioForCumulativeSalesResponse() { + val result = GetCumulativeSalesByContentQueryData( + nickname = "creator", + title = "content", + registrationDate = "2026-04-07", + orderType = OrderType.RENTAL, + orderPrice = 70, + numberOfPeople = 1, + totalCan = 100, + totalPoint = 0, + settlementRatio = null + ).toCumulativeSalesByContentItem() + + assertEquals("대여", result.orderType) + assertEquals(10_000, result.totalKrw) + assertEquals(660, result.paymentFee) + assertEquals(6_538, result.settlementAmount) + assertEquals(216, result.tax) + assertEquals(6_322, result.depositAmount) + } +}