크리에이터 정산 - 입력된 비율로 계산 #191
| @@ -4,6 +4,7 @@ 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.ratio.QCreatorSettlementRatio.creatorSettlementRatio | ||||
| import kr.co.vividnext.sodalive.can.use.CanUsage | ||||
| import kr.co.vividnext.sodalive.can.use.QUseCan.useCan | ||||
| import kr.co.vividnext.sodalive.content.QAudioContent.audioContent | ||||
| @@ -29,18 +30,21 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { | ||||
|                     liveRoom.price, | ||||
|                     useCan.canUsage, | ||||
|                     useCan.id.count(), | ||||
|                     useCan.can.add(useCan.rewardCan).sum() | ||||
|                     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(liveRoom.beginDateTime.goe(startDate)) | ||||
|                     .and(liveRoom.beginDateTime.loe(endDate)) | ||||
|             ) | ||||
|             .groupBy(liveRoom.id, useCan.canUsage) | ||||
|             .groupBy(liveRoom.id, useCan.canUsage, creatorSettlementRatio.liveSettlementRatio) | ||||
|             .orderBy(member.nickname.desc(), liveRoom.id.desc(), useCan.canUsage.desc(), formattedDate.desc()) | ||||
|             .fetch() | ||||
|     } | ||||
| @@ -57,18 +61,27 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { | ||||
|                     order.type, | ||||
|                     order.can, | ||||
|                     order.id.count(), | ||||
|                     order.can.sum() | ||||
|                     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(audioContent.id, order.type, orderFormattedDate, order.can) | ||||
|             .groupBy( | ||||
|                 audioContent.id, | ||||
|                 order.type, | ||||
|                 orderFormattedDate, | ||||
|                 order.can, | ||||
|                 creatorSettlementRatio.contentSettlementRatio | ||||
|             ) | ||||
|             .orderBy(member.id.desc(), orderFormattedDate.desc(), audioContent.id.asc()) | ||||
|             .fetch() | ||||
|     } | ||||
| @@ -187,19 +200,22 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { | ||||
|                     formattedDate, | ||||
|                     creatorCommunity.price, | ||||
|                     useCan.id.count(), | ||||
|                     useCan.can.add(useCan.rewardCan).sum() | ||||
|                     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(formattedDate, creatorCommunity.id) | ||||
|             .groupBy(formattedDate, creatorCommunity.id, creatorSettlementRatio.communitySettlementRatio) | ||||
|             .orderBy(member.id.asc(), formattedDate.desc()) | ||||
|             .offset(offset) | ||||
|             .limit(limit) | ||||
|   | ||||
| @@ -9,12 +9,17 @@ data class GetCalculateCommunityPostQueryData @QueryProjection constructor( | ||||
|     val date: String, | ||||
|     val can: Int, | ||||
|     val numberOfPurchase: Long, | ||||
|     val totalCan: Int | ||||
|     val totalCan: Int, | ||||
|     val settlementRatio: Int? | ||||
| ) { | ||||
|     fun toGetCalculateCommunityPostResponse(): GetCalculateCommunityPostResponse { | ||||
|         val totalKrw = totalCan * 100 | ||||
|         val paymentFee = totalKrw * 0.066f | ||||
|         val settlementAmount = (totalKrw.toFloat() - paymentFee) * 0.7 | ||||
|         val settlementAmount = if (settlementRatio != null) { | ||||
|             (totalKrw.toFloat() - paymentFee) * (settlementRatio.toFloat() / 100.0f) | ||||
|         } else { | ||||
|             (totalKrw.toFloat() - paymentFee) * 0.7f | ||||
|         } | ||||
|         val tax = settlementAmount * 0.033 | ||||
|         val depositAmount = settlementAmount - tax | ||||
|  | ||||
|   | ||||
| @@ -20,7 +20,9 @@ data class GetCalculateContentQueryData @QueryProjection constructor( | ||||
|     // 인원 | ||||
|     val numberOfPeople: Long, | ||||
|     // 합계 | ||||
|     val totalCan: Int | ||||
|     val totalCan: Int, | ||||
|     // 정산비율 | ||||
|     val settlementRatio: Int? | ||||
| ) { | ||||
|     fun toGetCalculateContentResponse(): GetCalculateContentResponse { | ||||
|         val orderTypeStr = if (orderType == OrderType.RENTAL) { | ||||
| @@ -36,7 +38,11 @@ data class GetCalculateContentQueryData @QueryProjection constructor( | ||||
|         val paymentFee = totalKrw * 0.066f | ||||
|  | ||||
|         // 정산금액 = (원화 - 결제수수료) 의 70% | ||||
|         val settlementAmount = (totalKrw.toFloat() - paymentFee) * 0.7 | ||||
|         val settlementAmount = if (settlementRatio != null) { | ||||
|             (totalKrw.toFloat() - paymentFee) * (settlementRatio.toFloat() / 100.0f) | ||||
|         } else { | ||||
|             (totalKrw.toFloat() - paymentFee) * 0.7f | ||||
|         } | ||||
|  | ||||
|         // 원천세 = 정산금액의 3.3% | ||||
|         val tax = settlementAmount * 0.033 | ||||
|   | ||||
| @@ -16,7 +16,9 @@ data class GetCalculateLiveQueryData @QueryProjection constructor( | ||||
|     // 참여인원 | ||||
|     val memberCount: Long, | ||||
|     // 합계 | ||||
|     val totalAmount: Int | ||||
|     val totalAmount: Int, | ||||
|     // 정산비율 | ||||
|     val settlementRatio: Int? | ||||
| ) { | ||||
|     fun toGetCalculateLiveResponse(): GetCalculateLiveResponse { | ||||
|         val canUsageStr = when (canUsage) { | ||||
| @@ -46,7 +48,11 @@ data class GetCalculateLiveQueryData @QueryProjection constructor( | ||||
|         val paymentFee = totalKrw * 0.066f | ||||
|  | ||||
|         // 정산금액 = (원화 - 결제수수료) 의 70% | ||||
|         val settlementAmount = (totalKrw.toFloat() - paymentFee) * 0.7 | ||||
|         val settlementAmount = if (settlementRatio != null) { | ||||
|             (totalKrw.toFloat() - paymentFee) * (settlementRatio.toFloat() / 100.0f) | ||||
|         } else { | ||||
|             (totalKrw.toFloat() - paymentFee) * 0.7f | ||||
|         } | ||||
|  | ||||
|         // 원천세 = 정산금액의 3.3% | ||||
|         val tax = settlementAmount * 0.033 | ||||
|   | ||||
| @@ -0,0 +1,16 @@ | ||||
| package kr.co.vividnext.sodalive.admin.calculate.ratio | ||||
|  | ||||
| data class CreateCreatorSettlementRatioRequest( | ||||
|     val memberId: Long, | ||||
|     val subsidy: Int, | ||||
|     val liveSettlementRatio: Int, | ||||
|     val contentSettlementRatio: Int, | ||||
|     val communitySettlementRatio: Int | ||||
| ) { | ||||
|     fun toEntity() = CreatorSettlementRatio( | ||||
|         subsidy = subsidy, | ||||
|         liveSettlementRatio = liveSettlementRatio, | ||||
|         contentSettlementRatio = contentSettlementRatio, | ||||
|         communitySettlementRatio = communitySettlementRatio | ||||
|     ) | ||||
| } | ||||
| @@ -0,0 +1,20 @@ | ||||
| package kr.co.vividnext.sodalive.admin.calculate.ratio | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.BaseEntity | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import javax.persistence.Entity | ||||
| import javax.persistence.FetchType | ||||
| import javax.persistence.JoinColumn | ||||
| import javax.persistence.OneToOne | ||||
|  | ||||
| @Entity | ||||
| data class CreatorSettlementRatio( | ||||
|     val subsidy: Int, | ||||
|     val liveSettlementRatio: Int, | ||||
|     val contentSettlementRatio: Int, | ||||
|     val communitySettlementRatio: Int | ||||
| ) : BaseEntity() { | ||||
|     @OneToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "member_id", nullable = false) | ||||
|     var member: Member? = null | ||||
| } | ||||
| @@ -0,0 +1,30 @@ | ||||
| package kr.co.vividnext.sodalive.admin.calculate.ratio | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.ApiResponse | ||||
| import org.springframework.data.domain.Pageable | ||||
| import org.springframework.security.access.prepost.PreAuthorize | ||||
| import org.springframework.web.bind.annotation.GetMapping | ||||
| import org.springframework.web.bind.annotation.PostMapping | ||||
| import org.springframework.web.bind.annotation.RequestBody | ||||
| import org.springframework.web.bind.annotation.RequestMapping | ||||
| import org.springframework.web.bind.annotation.RestController | ||||
|  | ||||
| @RestController | ||||
| @PreAuthorize("hasRole('ADMIN')") | ||||
| @RequestMapping("/admin/calculate/ratio") | ||||
| class CreatorSettlementRatioController(private val service: CreatorSettlementRatioService) { | ||||
|     @PostMapping | ||||
|     fun createCreatorSettlementRatio( | ||||
|         @RequestBody request: CreateCreatorSettlementRatioRequest | ||||
|     ) = ApiResponse.ok(service.createCreatorSettlementRatio(request)) | ||||
|  | ||||
|     @GetMapping | ||||
|     fun getCreatorSettlementRatio( | ||||
|         pageable: Pageable | ||||
|     ) = ApiResponse.ok( | ||||
|         service.getCreatorSettlementRatio( | ||||
|             offset = pageable.offset, | ||||
|             limit = pageable.pageSize.toLong() | ||||
|         ) | ||||
|     ) | ||||
| } | ||||
| @@ -0,0 +1,46 @@ | ||||
| package kr.co.vividnext.sodalive.admin.calculate.ratio | ||||
|  | ||||
| import com.querydsl.jpa.impl.JPAQueryFactory | ||||
| import kr.co.vividnext.sodalive.admin.calculate.ratio.QCreatorSettlementRatio.creatorSettlementRatio | ||||
| import kr.co.vividnext.sodalive.member.QMember.member | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
|  | ||||
| interface CreatorSettlementRatioRepository : | ||||
|     JpaRepository<CreatorSettlementRatio, Long>, | ||||
|     CreatorSettlementRatioQueryRepository | ||||
|  | ||||
| interface CreatorSettlementRatioQueryRepository { | ||||
|     fun getCreatorSettlementRatio(offset: Long, limit: Long): List<GetCreatorSettlementRatioItem> | ||||
|     fun getCreatorSettlementRatioTotalCount(): Int | ||||
| } | ||||
|  | ||||
| class CreatorSettlementRatioQueryRepositoryImpl( | ||||
|     private val queryFactory: JPAQueryFactory | ||||
| ) : CreatorSettlementRatioQueryRepository { | ||||
|     override fun getCreatorSettlementRatio(offset: Long, limit: Long): List<GetCreatorSettlementRatioItem> { | ||||
|         return queryFactory | ||||
|             .select( | ||||
|                 QGetCreatorSettlementRatioItem( | ||||
|                     member.nickname, | ||||
|                     creatorSettlementRatio.subsidy, | ||||
|                     creatorSettlementRatio.liveSettlementRatio, | ||||
|                     creatorSettlementRatio.contentSettlementRatio, | ||||
|                     creatorSettlementRatio.communitySettlementRatio | ||||
|                 ) | ||||
|             ) | ||||
|             .from(creatorSettlementRatio) | ||||
|             .innerJoin(creatorSettlementRatio.member, member) | ||||
|             .orderBy(creatorSettlementRatio.id.asc()) | ||||
|             .offset(offset) | ||||
|             .limit(limit) | ||||
|             .fetch() | ||||
|     } | ||||
|  | ||||
|     override fun getCreatorSettlementRatioTotalCount(): Int { | ||||
|         return queryFactory | ||||
|             .select(creatorSettlementRatio.id) | ||||
|             .from(creatorSettlementRatio) | ||||
|             .fetch() | ||||
|             .size | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,37 @@ | ||||
| package kr.co.vividnext.sodalive.admin.calculate.ratio | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.member.MemberRepository | ||||
| import kr.co.vividnext.sodalive.member.MemberRole | ||||
| import org.springframework.data.repository.findByIdOrNull | ||||
| import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | ||||
|  | ||||
| @Service | ||||
| class CreatorSettlementRatioService( | ||||
|     private val repository: CreatorSettlementRatioRepository, | ||||
|     private val memberRepository: MemberRepository | ||||
| ) { | ||||
|     @Transactional | ||||
|     fun createCreatorSettlementRatio(request: CreateCreatorSettlementRatioRequest) { | ||||
|         val creatorSettlementRatio = request.toEntity() | ||||
|  | ||||
|         val creator = memberRepository.findByIdOrNull(request.memberId) | ||||
|             ?: throw SodaException("잘못된 크리에이터 입니다.") | ||||
|  | ||||
|         if (creator.role != MemberRole.CREATOR) { | ||||
|             throw SodaException("잘못된 크리에이터 입니다.") | ||||
|         } | ||||
|  | ||||
|         creatorSettlementRatio.member = creator | ||||
|         repository.save(creatorSettlementRatio) | ||||
|     } | ||||
|  | ||||
|     @Transactional(readOnly = true) | ||||
|     fun getCreatorSettlementRatio(offset: Long, limit: Long): GetCreatorSettlementRatioResponse { | ||||
|         val totalCount = repository.getCreatorSettlementRatioTotalCount() | ||||
|         val items = repository.getCreatorSettlementRatio(offset, limit) | ||||
|  | ||||
|         return GetCreatorSettlementRatioResponse(totalCount, items) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,16 @@ | ||||
| package kr.co.vividnext.sodalive.admin.calculate.ratio | ||||
|  | ||||
| import com.querydsl.core.annotations.QueryProjection | ||||
|  | ||||
| data class GetCreatorSettlementRatioResponse( | ||||
|     val totalCount: Int, | ||||
|     val items: List<GetCreatorSettlementRatioItem> | ||||
| ) | ||||
|  | ||||
| data class GetCreatorSettlementRatioItem @QueryProjection constructor( | ||||
|     val nickname: String, | ||||
|     val subsidy: Int, | ||||
|     val liveSettlementRatio: Int, | ||||
|     val contentSettlementRatio: Int, | ||||
|     val communitySettlementRatio: Int | ||||
| ) | ||||
| @@ -14,6 +14,7 @@ import kr.co.vividnext.sodalive.admin.calculate.QGetCalculateContentDonationQuer | ||||
| 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.admin.calculate.ratio.QCreatorSettlementRatio.creatorSettlementRatio | ||||
| import kr.co.vividnext.sodalive.can.use.CanUsage | ||||
| import kr.co.vividnext.sodalive.can.use.QUseCan.useCan | ||||
| import kr.co.vividnext.sodalive.content.QAudioContent.audioContent | ||||
| @@ -43,19 +44,22 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac | ||||
|                     liveRoom.price, | ||||
|                     useCan.canUsage, | ||||
|                     useCan.id.count(), | ||||
|                     useCan.can.add(useCan.rewardCan).sum() | ||||
|                     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(liveRoom.beginDateTime.goe(startDate)) | ||||
|                     .and(liveRoom.beginDateTime.loe(endDate)) | ||||
|                     .and(liveRoom.member.id.eq(memberId)) | ||||
|             ) | ||||
|             .groupBy(liveRoom.id, useCan.canUsage) | ||||
|             .groupBy(liveRoom.id, useCan.canUsage, creatorSettlementRatio.liveSettlementRatio) | ||||
|             .orderBy(liveRoom.id.desc(), useCan.canUsage.desc(), formattedDate.desc()) | ||||
|             .fetch() | ||||
|     } | ||||
| @@ -101,19 +105,28 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac | ||||
|                     order.type, | ||||
|                     order.can, | ||||
|                     order.id.count(), | ||||
|                     order.can.sum() | ||||
|                     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) | ||||
|                     .and(order.creator.id.eq(memberId)) | ||||
|             ) | ||||
|             .groupBy(audioContent.id, order.type, orderFormattedDate, order.can) | ||||
|             .groupBy( | ||||
|                 audioContent.id, | ||||
|                 order.type, | ||||
|                 orderFormattedDate, | ||||
|                 order.can, | ||||
|                 creatorSettlementRatio.contentSettlementRatio | ||||
|             ) | ||||
|             .offset(offset) | ||||
|             .limit(limit) | ||||
|             .orderBy(member.id.desc(), orderFormattedDate.desc(), audioContent.id.asc()) | ||||
| @@ -275,12 +288,15 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac | ||||
|                     formattedDate, | ||||
|                     creatorCommunity.price, | ||||
|                     useCan.id.count(), | ||||
|                     useCan.can.add(useCan.rewardCan).sum() | ||||
|                     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)) | ||||
| @@ -288,7 +304,7 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac | ||||
|                     .and(useCan.createdAt.loe(endDate)) | ||||
|                     .and(creatorCommunity.member.id.eq(memberId)) | ||||
|             ) | ||||
|             .groupBy(formattedDate, creatorCommunity.id) | ||||
|             .groupBy(formattedDate, creatorCommunity.id, creatorSettlementRatio.communitySettlementRatio) | ||||
|             .orderBy(member.id.asc(), formattedDate.desc()) | ||||
|             .offset(offset) | ||||
|             .limit(limit) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user