| @@ -16,4 +16,10 @@ class AdminCalculateController(private val service: AdminCalculateService) { | |||||||
|         @RequestParam startDateStr: String, |         @RequestParam startDateStr: String, | ||||||
|         @RequestParam endDateStr: String |         @RequestParam endDateStr: String | ||||||
|     ) = ApiResponse.ok(service.getCalculateLive(startDateStr, endDateStr)) |     ) = ApiResponse.ok(service.getCalculateLive(startDateStr, endDateStr)) | ||||||
|  |  | ||||||
|  |     @GetMapping("/content-list") | ||||||
|  |     fun getCalculateContentList( | ||||||
|  |         @RequestParam startDateStr: String, | ||||||
|  |         @RequestParam endDateStr: String | ||||||
|  |     ) = ApiResponse.ok(service.getCalculateContentList(startDateStr, endDateStr)) | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,10 +1,14 @@ | |||||||
| package kr.co.vividnext.sodalive.admin.calculate | package kr.co.vividnext.sodalive.admin.calculate | ||||||
|  |  | ||||||
|  | import com.querydsl.core.types.dsl.DateTimePath | ||||||
| import com.querydsl.core.types.dsl.Expressions | import com.querydsl.core.types.dsl.Expressions | ||||||
|  | import com.querydsl.core.types.dsl.StringTemplate | ||||||
| import com.querydsl.jpa.impl.JPAQueryFactory | import com.querydsl.jpa.impl.JPAQueryFactory | ||||||
| import kr.co.vividnext.sodalive.can.use.QUseCan.useCan | 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.QUseCanCalculate.useCanCalculate | ||||||
| import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus | import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus | ||||||
|  | import kr.co.vividnext.sodalive.content.QAudioContent.audioContent | ||||||
|  | import kr.co.vividnext.sodalive.content.order.QOrder.order | ||||||
| import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom | import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom | ||||||
| import kr.co.vividnext.sodalive.member.QMember.member | import kr.co.vividnext.sodalive.member.QMember.member | ||||||
| import org.springframework.stereotype.Repository | import org.springframework.stereotype.Repository | ||||||
| @@ -13,17 +17,7 @@ import java.time.LocalDateTime | |||||||
| @Repository | @Repository | ||||||
| class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { | class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { | ||||||
|     fun getCalculateLive(startDate: LocalDateTime, endDate: LocalDateTime): List<GetCalculateLiveQueryData> { |     fun getCalculateLive(startDate: LocalDateTime, endDate: LocalDateTime): List<GetCalculateLiveQueryData> { | ||||||
|         val formattedDate = Expressions.stringTemplate( |         val formattedDate = getFormattedDate(liveRoom.beginDateTime) | ||||||
|             "DATE_FORMAT({0}, {1})", |  | ||||||
|             Expressions.dateTimeTemplate( |  | ||||||
|                 LocalDateTime::class.java, |  | ||||||
|                 "CONVERT_TZ({0},{1},{2})", |  | ||||||
|                 liveRoom.beginDateTime, |  | ||||||
|                 "UTC", |  | ||||||
|                 "Asia/Seoul" |  | ||||||
|             ), |  | ||||||
|             "%Y-%m-%d" |  | ||||||
|         ) |  | ||||||
|  |  | ||||||
|         return queryFactory |         return queryFactory | ||||||
|             .select( |             .select( | ||||||
| @@ -51,4 +45,48 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { | |||||||
|             .orderBy(member.nickname.desc(), formattedDate.desc()) |             .orderBy(member.nickname.desc(), formattedDate.desc()) | ||||||
|             .fetch() |             .fetch() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fun getCalculateContentList(startDate: LocalDateTime, endDate: LocalDateTime): List<GetCalculateContentQueryData> { | ||||||
|  |         val orderFormattedDate = getFormattedDate(order.createdAt) | ||||||
|  |         return queryFactory | ||||||
|  |             .select( | ||||||
|  |                 QGetCalculateContentQueryData( | ||||||
|  |                     member.nickname, | ||||||
|  |                     audioContent.title, | ||||||
|  |                     getFormattedDate(audioContent.createdAt), | ||||||
|  |                     orderFormattedDate, | ||||||
|  |                     order.type, | ||||||
|  |                     order.can, | ||||||
|  |                     order.id.count(), | ||||||
|  |                     order.can.sum() | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |             .from(useCanCalculate) | ||||||
|  |             .innerJoin(useCanCalculate.useCan, useCan) | ||||||
|  |             .innerJoin(useCan.order, order) | ||||||
|  |             .innerJoin(order.audioContent, audioContent) | ||||||
|  |             .innerJoin(audioContent.member, member) | ||||||
|  |             .where( | ||||||
|  |                 useCanCalculate.status.eq(UseCanCalculateStatus.RECEIVED) | ||||||
|  |                     .and(order.createdAt.goe(startDate)) | ||||||
|  |                     .and(order.createdAt.loe(endDate)) | ||||||
|  |             ) | ||||||
|  |             .groupBy(audioContent.id, order.type, order.createdAt, order.can) | ||||||
|  |             .orderBy(member.id.desc(), orderFormattedDate.desc()) | ||||||
|  |             .fetch() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun getFormattedDate(dateTimePath: DateTimePath<LocalDateTime>): StringTemplate { | ||||||
|  |         return Expressions.stringTemplate( | ||||||
|  |             "DATE_FORMAT({0}, {1})", | ||||||
|  |             Expressions.dateTimeTemplate( | ||||||
|  |                 LocalDateTime::class.java, | ||||||
|  |                 "CONVERT_TZ({0},{1},{2})", | ||||||
|  |                 dateTimePath, | ||||||
|  |                 "UTC", | ||||||
|  |                 "Asia/Seoul" | ||||||
|  |             ), | ||||||
|  |             "%Y-%m-%d" | ||||||
|  |         ) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -1,6 +1,7 @@ | |||||||
| package kr.co.vividnext.sodalive.admin.calculate | package kr.co.vividnext.sodalive.admin.calculate | ||||||
|  |  | ||||||
| import kr.co.vividnext.sodalive.can.use.CanUsage | import kr.co.vividnext.sodalive.can.use.CanUsage | ||||||
|  | import kr.co.vividnext.sodalive.content.order.OrderType | ||||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||||
| import java.time.LocalDate | import java.time.LocalDate | ||||||
| import java.time.ZoneId | import java.time.ZoneId | ||||||
| @@ -70,4 +71,59 @@ class AdminCalculateService(private val repository: AdminCalculateQueryRepositor | |||||||
|             } |             } | ||||||
|             .toList() |             .toList() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fun getCalculateContentList(startDateStr: String, endDateStr: String): List<GetCalculateContentResponse> { | ||||||
|  |         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() | ||||||
|  |  | ||||||
|  |         return repository | ||||||
|  |             .getCalculateContentList(startDate, endDate) | ||||||
|  |             .map { | ||||||
|  |                 val orderTypeStr = if (it.orderType == OrderType.RENTAL) { | ||||||
|  |                     "대여" | ||||||
|  |                 } else { | ||||||
|  |                     "소장" | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 // 원화 = 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 | ||||||
|  |  | ||||||
|  |                 GetCalculateContentResponse( | ||||||
|  |                     nickname = it.nickname, | ||||||
|  |                     title = it.title, | ||||||
|  |                     registrationDate = it.registrationDate, | ||||||
|  |                     saleDate = it.saleDate, | ||||||
|  |                     orderType = orderTypeStr, | ||||||
|  |                     orderPrice = it.orderPrice, | ||||||
|  |                     numberOfPeople = it.numberOfPeople.toInt(), | ||||||
|  |                     totalCan = it.totalCan, | ||||||
|  |                     totalKrw = totalKrw, | ||||||
|  |                     paymentFee = paymentFee.roundToInt(), | ||||||
|  |                     settlementAmount = settlementAmount.roundToInt(), | ||||||
|  |                     tax = tax.roundToInt(), | ||||||
|  |                     depositAmount = depositAmount.roundToInt() | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             .toList() | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,23 @@ | |||||||
|  | package kr.co.vividnext.sodalive.admin.calculate | ||||||
|  |  | ||||||
|  | import com.querydsl.core.annotations.QueryProjection | ||||||
|  | import kr.co.vividnext.sodalive.content.order.OrderType | ||||||
|  |  | ||||||
|  | data class GetCalculateContentQueryData @QueryProjection constructor( | ||||||
|  |     // 등록 크리에이터 닉네임 | ||||||
|  |     val nickname: String, | ||||||
|  |     // 콘텐츠 제목 | ||||||
|  |     val title: String, | ||||||
|  |     // 콘텐츠 등록 날짜 | ||||||
|  |     val registrationDate: String, | ||||||
|  |     // 콘텐츠 판매 날짜 | ||||||
|  |     val saleDate: String, | ||||||
|  |     // 대여/소장 구분 | ||||||
|  |     val orderType: OrderType, | ||||||
|  |     // 판매 금액(캔) | ||||||
|  |     val orderPrice: Int, | ||||||
|  |     // 인원 | ||||||
|  |     val numberOfPeople: Long, | ||||||
|  |     // 합계 | ||||||
|  |     val totalCan: Int | ||||||
|  | ) | ||||||
| @@ -0,0 +1,30 @@ | |||||||
|  | package kr.co.vividnext.sodalive.admin.calculate | ||||||
|  |  | ||||||
|  | data class GetCalculateContentResponse( | ||||||
|  |     // 등록 크리에이터 닉네임 | ||||||
|  |     val nickname: String, | ||||||
|  |     // 콘텐츠 제목 | ||||||
|  |     val title: String, | ||||||
|  |     // 콘텐츠 등록 날짜 | ||||||
|  |     val registrationDate: String, | ||||||
|  |     // 콘텐츠 판매 날짜 | ||||||
|  |     val saleDate: String, | ||||||
|  |     // 대여/소장 구분 | ||||||
|  |     val orderType: String, | ||||||
|  |     // 판매 금액(캔) | ||||||
|  |     val orderPrice: Int, | ||||||
|  |     // 인원 | ||||||
|  |     val numberOfPeople: Int, | ||||||
|  |     // 합계 | ||||||
|  |     val totalCan: Int, | ||||||
|  |     // 원화 | ||||||
|  |     val totalKrw: Int, | ||||||
|  |     // 수수료 | ||||||
|  |     val paymentFee: Int, | ||||||
|  |     // 정산금액 | ||||||
|  |     val settlementAmount: Int, | ||||||
|  |     // 원천세(세금 3.3%) | ||||||
|  |     val tax: Int, | ||||||
|  |     // 입금액 | ||||||
|  |     val depositAmount: Int | ||||||
|  | ) | ||||||
		Reference in New Issue
	
	Block a user