From 1dec8913c5e8444b1e4d2026f7be97ce34b0cf95 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 14 Mar 2025 21:48:52 +0900 Subject: [PATCH 1/6] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20-=20=EC=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A0=84=EC=B2=B4=20=ED=9A=8C=EC=9B=90=EC=88=98=20?= =?UTF-8?q?API=20-=20=EC=9D=BC=EB=B3=84=20=ED=9A=8C=EC=9B=90=EA=B0=80?= =?UTF-8?q?=EC=9E=85,=20=ED=9A=8C=EC=9B=90=ED=83=88=ED=87=B4,=20=EA=B2=B0?= =?UTF-8?q?=EC=A0=9C=EC=9E=90=20=EC=88=98=EB=A5=BC=20=EB=B0=98=ED=99=98?= =?UTF-8?q?=ED=95=98=EB=8A=94=20API=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/AdminMemberStatisticsController.kt | 28 +++++ .../member/AdminMemberStatisticsRepository.kt | 110 ++++++++++++++++++ .../member/AdminMemberStatisticsService.kt | 94 +++++++++++++++ .../statistics/member/DateAndMemberCount.kt | 8 ++ .../member/GetMemberStatisticsResponse.kt | 16 +++ .../admin/statistics/member/PagedDateRange.kt | 9 ++ 6 files changed, 265 insertions(+) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsController.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/DateAndMemberCount.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/GetMemberStatisticsResponse.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/PagedDateRange.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsController.kt new file mode 100644 index 0000000..ccab70f --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsController.kt @@ -0,0 +1,28 @@ +package kr.co.vividnext.sodalive.admin.statistics.member + +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.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController + +@RestController +@PreAuthorize("hasRole('ADMIN')") +@RequestMapping("/admin/member/statistics") +class AdminMemberStatisticsController(private val service: AdminMemberStatisticsService) { + @GetMapping + fun getStatistics( + @RequestParam startDateStr: String, + @RequestParam endDateStr: String, + pageable: Pageable + ) = ApiResponse.ok( + service.getStatistics( + startDateStr = startDateStr, + endDateStr = endDateStr, + offset = pageable.offset, + limit = pageable.pageSize.toLong() + ) + ) +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt new file mode 100644 index 0000000..d0e55db --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt @@ -0,0 +1,110 @@ +package kr.co.vividnext.sodalive.admin.statistics.member + +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.can.charge.ChargeStatus +import kr.co.vividnext.sodalive.can.charge.QCharge.charge +import kr.co.vividnext.sodalive.can.payment.PaymentStatus +import kr.co.vividnext.sodalive.can.payment.QPayment.payment +import kr.co.vividnext.sodalive.member.QMember.member +import kr.co.vividnext.sodalive.member.QSignOut.signOut +import org.springframework.stereotype.Repository +import java.time.LocalDateTime + +@Repository +class AdminMemberStatisticsRepository(private val queryFactory: JPAQueryFactory) { + fun getTotalSignUpCount(startDate: LocalDateTime, endDate: LocalDateTime): Int { + return queryFactory + .select(member.id) + .from(member) + .where( + member.createdAt.goe(startDate), + member.createdAt.loe(endDate) + ) + .fetch() + .size + } + + fun getTotalSignOutCount(startDate: LocalDateTime, endDate: LocalDateTime): Int { + return queryFactory + .select(signOut.id) + .from(signOut) + .where( + signOut.createdAt.goe(startDate), + signOut.createdAt.loe(endDate) + ) + .fetch() + .size + } + + fun getSignUpCountInRange(startDate: LocalDateTime, endDate: LocalDateTime): List { + return queryFactory + .select( + QDateAndMemberCount( + getFormattedDate(member.createdAt), + member.id.countDistinct().castToNum(Int::class.java) + ) + ) + .from(member) + .where( + member.createdAt.goe(startDate), + member.createdAt.loe(endDate) + ) + .groupBy(getFormattedDate(member.createdAt)) + .fetch() + } + + fun getSignOutCountInRange(startDate: LocalDateTime, endDate: LocalDateTime): List { + return queryFactory + .select( + QDateAndMemberCount( + getFormattedDate(signOut.createdAt), + signOut.id.countDistinct().castToNum(Int::class.java) + ) + ) + .from(signOut) + .where( + signOut.createdAt.goe(startDate), + signOut.createdAt.loe(endDate) + ) + .groupBy(getFormattedDate(signOut.createdAt)) + .fetch() + } + + fun getPaymentMemberCountInRange(startDate: LocalDateTime, endDate: LocalDateTime): List { + return queryFactory + .select( + QDateAndMemberCount( + getFormattedDate(charge.createdAt), + member.id.countDistinct().castToNum(Int::class.java) + ) + ) + .from(charge) + .innerJoin(charge.member, member) + .leftJoin(charge.payment, payment) + .where( + charge.status.eq(ChargeStatus.CHARGE), + payment.status.eq(PaymentStatus.COMPLETE), + charge.createdAt.goe(startDate), + charge.createdAt.loe(endDate) + ) + .groupBy(getFormattedDate(charge.createdAt)) + .fetch() + } + + private fun getFormattedDate(dateTimePath: DateTimePath): 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" + ) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt new file mode 100644 index 0000000..d61f1da --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt @@ -0,0 +1,94 @@ +package kr.co.vividnext.sodalive.admin.statistics.member + +import kr.co.vividnext.sodalive.common.SodaException +import org.springframework.stereotype.Service +import java.time.LocalDate +import java.time.LocalTime +import java.time.ZoneId +import java.time.format.DateTimeFormatter +import java.time.temporal.ChronoUnit + +@Service +class AdminMemberStatisticsService(private val repository: AdminMemberStatisticsRepository) { + fun getStatistics( + startDateStr: String, + endDateStr: String, + offset: Long, + limit: Long + ): GetMemberStatisticsResponse { + val dateRange = getPagedDateRange( + startDate = startDateStr, + endDate = endDateStr, + page = (offset + 1).toInt(), + pageSize = limit.toInt() + ) + + if (dateRange == null) { + throw SodaException("잘못된 접근입니다.") + } + + val startDate = dateRange.startDate + .atZone(ZoneId.of("Asia/Seoul")) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + + val endDate = dateRange.endDate + .atZone(ZoneId.of("Asia/Seoul")) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + + val totalSignUpCount = repository.getTotalSignUpCount(startDate = startDate, endDate = endDate) + val totalSignOutCount = repository.getTotalSignOutCount(startDate = startDate, endDate = endDate) + + val signUpCountInRange = repository.getSignUpCountInRange(startDate = startDate, endDate = endDate) + .associateBy({ it.date }, { it.memberCount }) + + val signOutCountInRange = repository.getSignOutCountInRange(startDate = startDate, endDate = endDate) + .associateBy({ it.date }, { it.memberCount }) + + val paymentMemberCountInRange = repository.getPaymentMemberCountInRange( + startDate = startDate, + endDate = endDate + ) + + val totalPaymentMemberCount = paymentMemberCountInRange.sumOf { it.memberCount } + val paymentMemberCountInRangeMap = paymentMemberCountInRange.associateBy({ it.date }, { it.memberCount }) + + val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") + val items = generateSequence(dateRange.startDate) { it.plusDays(1) } + .takeWhile { !it.isAfter(dateRange.endDate) } + .map { + val date = it.format(formatter) + GetMemberStatisticsItem( + date = date, + signUpCount = signUpCountInRange[date] ?: 0, + signOutCount = signOutCountInRange[date] ?: 0, + paymentMemberCount = paymentMemberCountInRangeMap[date] ?: 0 + ) + } + .toList() + + return GetMemberStatisticsResponse( + totalCount = dateRange.totalDays, + totalSignUpCount = totalSignUpCount, + totalSignOutCount = totalSignOutCount, + totalPaymentMemberCount = totalPaymentMemberCount, + items = items + ) + } + + private fun getPagedDateRange(startDate: String, endDate: String, page: Int, pageSize: Int): PagedDateRange? { + val start = LocalDate.parse(startDate) + val end = LocalDate.parse(endDate) + + val totalDays = ChronoUnit.DAYS.between(start, end).toInt() + 1 + val totalPages = (totalDays + pageSize - 1) / pageSize // 전체 페이지 개수 계산 + + if (page < 1 || page > totalPages) return null // 페이지 범위를 벗어나면 null 반환 + + val rangeStart = start.plusDays((page - 1) * pageSize.toLong()).atStartOfDay() + val rangeEnd = start.plusDays((page * pageSize - 1).toLong()).coerceAtMost(end).atTime(LocalTime.MAX) + + return PagedDateRange(rangeStart, rangeEnd, totalDays) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/DateAndMemberCount.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/DateAndMemberCount.kt new file mode 100644 index 0000000..531db9a --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/DateAndMemberCount.kt @@ -0,0 +1,8 @@ +package kr.co.vividnext.sodalive.admin.statistics.member + +import com.querydsl.core.annotations.QueryProjection + +data class DateAndMemberCount @QueryProjection constructor( + val date: String, + val memberCount: Int +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/GetMemberStatisticsResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/GetMemberStatisticsResponse.kt new file mode 100644 index 0000000..7a0d7ea --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/GetMemberStatisticsResponse.kt @@ -0,0 +1,16 @@ +package kr.co.vividnext.sodalive.admin.statistics.member + +data class GetMemberStatisticsResponse( + val totalCount: Int, + val totalSignUpCount: Int, + val totalSignOutCount: Int, + val totalPaymentMemberCount: Int, + val items: List +) + +data class GetMemberStatisticsItem( + val date: String, + val signUpCount: Int, + val signOutCount: Int, + val paymentMemberCount: Int +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/PagedDateRange.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/PagedDateRange.kt new file mode 100644 index 0000000..8bc8609 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/PagedDateRange.kt @@ -0,0 +1,9 @@ +package kr.co.vividnext.sodalive.admin.statistics.member + +import java.time.LocalDateTime + +data class PagedDateRange( + val startDate: LocalDateTime, + val endDate: LocalDateTime, + val totalDays: Int +) -- 2.40.1 From 74fecddf95d5d31b9218b399e5c57398336f1127 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 14 Mar 2025 23:55:04 +0900 Subject: [PATCH 2/6] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20-=20=EC=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A0=84=EC=B2=B4=20=ED=9A=8C=EC=9B=90=EC=88=98=20?= =?UTF-8?q?API=20-=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EA=B3=84=EC=82=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/AdminMemberStatisticsController.kt | 3 +- .../member/AdminMemberStatisticsRepository.kt | 113 ++++++++++++------ .../member/AdminMemberStatisticsService.kt | 30 +++-- 3 files changed, 99 insertions(+), 47 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsController.kt index ccab70f..d3ffdc3 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsController.kt @@ -21,8 +21,7 @@ class AdminMemberStatisticsController(private val service: AdminMemberStatistics service.getStatistics( startDateStr = startDateStr, endDateStr = endDateStr, - offset = pageable.offset, - limit = pageable.pageSize.toLong() + pageable = pageable ) ) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt index d0e55db..3389986 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt @@ -39,41 +39,7 @@ class AdminMemberStatisticsRepository(private val queryFactory: JPAQueryFactory) .size } - fun getSignUpCountInRange(startDate: LocalDateTime, endDate: LocalDateTime): List { - return queryFactory - .select( - QDateAndMemberCount( - getFormattedDate(member.createdAt), - member.id.countDistinct().castToNum(Int::class.java) - ) - ) - .from(member) - .where( - member.createdAt.goe(startDate), - member.createdAt.loe(endDate) - ) - .groupBy(getFormattedDate(member.createdAt)) - .fetch() - } - - fun getSignOutCountInRange(startDate: LocalDateTime, endDate: LocalDateTime): List { - return queryFactory - .select( - QDateAndMemberCount( - getFormattedDate(signOut.createdAt), - signOut.id.countDistinct().castToNum(Int::class.java) - ) - ) - .from(signOut) - .where( - signOut.createdAt.goe(startDate), - signOut.createdAt.loe(endDate) - ) - .groupBy(getFormattedDate(signOut.createdAt)) - .fetch() - } - - fun getPaymentMemberCountInRange(startDate: LocalDateTime, endDate: LocalDateTime): List { + fun getPaymentMemberCount(startDate: LocalDateTime, endDate: LocalDateTime): Int { return queryFactory .select( QDateAndMemberCount( @@ -92,6 +58,83 @@ class AdminMemberStatisticsRepository(private val queryFactory: JPAQueryFactory) ) .groupBy(getFormattedDate(charge.createdAt)) .fetch() + .sumOf { it.memberCount } + } + + fun getSignUpCountInRange( + startDate: LocalDateTime, + endDate: LocalDateTime, + offset: Long, + limit: Long + ): List { + return queryFactory + .select( + QDateAndMemberCount( + getFormattedDate(member.createdAt), + member.id.countDistinct().castToNum(Int::class.java) + ) + ) + .from(member) + .where( + member.createdAt.goe(startDate), + member.createdAt.loe(endDate) + ) + .groupBy(getFormattedDate(member.createdAt)) + .offset(offset) + .limit(limit) + .fetch() + } + + fun getSignOutCountInRange( + startDate: LocalDateTime, + endDate: LocalDateTime, + offset: Long, + limit: Long + ): List { + return queryFactory + .select( + QDateAndMemberCount( + getFormattedDate(signOut.createdAt), + signOut.id.countDistinct().castToNum(Int::class.java) + ) + ) + .from(signOut) + .where( + signOut.createdAt.goe(startDate), + signOut.createdAt.loe(endDate) + ) + .groupBy(getFormattedDate(signOut.createdAt)) + .offset(offset) + .limit(limit) + .fetch() + } + + fun getPaymentMemberCountInRange( + startDate: LocalDateTime, + endDate: LocalDateTime, + offset: Long, + limit: Long + ): List { + return queryFactory + .select( + QDateAndMemberCount( + getFormattedDate(charge.createdAt), + member.id.countDistinct().castToNum(Int::class.java) + ) + ) + .from(charge) + .innerJoin(charge.member, member) + .leftJoin(charge.payment, payment) + .where( + charge.status.eq(ChargeStatus.CHARGE), + payment.status.eq(PaymentStatus.COMPLETE), + charge.createdAt.goe(startDate), + charge.createdAt.loe(endDate) + ) + .groupBy(getFormattedDate(charge.createdAt)) + .offset(offset) + .limit(limit) + .fetch() } private fun getFormattedDate(dateTimePath: DateTimePath): StringTemplate { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt index d61f1da..319b9b3 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt @@ -1,6 +1,7 @@ package kr.co.vividnext.sodalive.admin.statistics.member import kr.co.vividnext.sodalive.common.SodaException +import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service import java.time.LocalDate import java.time.LocalTime @@ -13,14 +14,13 @@ class AdminMemberStatisticsService(private val repository: AdminMemberStatistics fun getStatistics( startDateStr: String, endDateStr: String, - offset: Long, - limit: Long + pageable: Pageable ): GetMemberStatisticsResponse { val dateRange = getPagedDateRange( startDate = startDateStr, endDate = endDateStr, - page = (offset + 1).toInt(), - pageSize = limit.toInt() + page = pageable.pageNumber + 1, + pageSize = pageable.pageSize ) if (dateRange == null) { @@ -39,19 +39,29 @@ class AdminMemberStatisticsService(private val repository: AdminMemberStatistics val totalSignUpCount = repository.getTotalSignUpCount(startDate = startDate, endDate = endDate) val totalSignOutCount = repository.getTotalSignOutCount(startDate = startDate, endDate = endDate) + val totalPaymentMemberCount = repository.getPaymentMemberCount(startDate = startDate, endDate = endDate) - val signUpCountInRange = repository.getSignUpCountInRange(startDate = startDate, endDate = endDate) - .associateBy({ it.date }, { it.memberCount }) + val signUpCountInRange = repository.getSignUpCountInRange( + startDate = startDate, + endDate = endDate, + offset = pageable.offset, + limit = pageable.pageSize.toLong() + ).associateBy({ it.date }, { it.memberCount }) - val signOutCountInRange = repository.getSignOutCountInRange(startDate = startDate, endDate = endDate) - .associateBy({ it.date }, { it.memberCount }) + val signOutCountInRange = repository.getSignOutCountInRange( + startDate = startDate, + endDate = endDate, + offset = pageable.offset, + limit = pageable.pageSize.toLong() + ).associateBy({ it.date }, { it.memberCount }) val paymentMemberCountInRange = repository.getPaymentMemberCountInRange( startDate = startDate, - endDate = endDate + endDate = endDate, + offset = pageable.offset, + limit = pageable.pageSize.toLong() ) - val totalPaymentMemberCount = paymentMemberCountInRange.sumOf { it.memberCount } val paymentMemberCountInRangeMap = paymentMemberCountInRange.associateBy({ it.date }, { it.memberCount }) val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") -- 2.40.1 From 3a180d478c4e54ff8f6c27137e166580d6670cc5 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sat, 15 Mar 2025 00:09:35 +0900 Subject: [PATCH 3/6] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20-=20=EC=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A0=84=EC=B2=B4=20=ED=9A=8C=EC=9B=90=EC=88=98=20?= =?UTF-8?q?API=20-=20=ED=95=A9=EA=B3=84=20=EB=82=A0=EC=A7=9C=20=EB=B2=94?= =?UTF-8?q?=EC=9C=84=EB=A5=BC=20=EC=A0=84=EC=B2=B4=20=EB=82=A0=EC=A7=9C=20?= =?UTF-8?q?=EB=B2=94=EC=9C=84=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/AdminMemberStatisticsService.kt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt index 319b9b3..754a013 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsService.kt @@ -27,12 +27,12 @@ class AdminMemberStatisticsService(private val repository: AdminMemberStatistics throw SodaException("잘못된 접근입니다.") } - val startDate = dateRange.startDate + var startDate = LocalDate.parse(startDateStr).atStartOfDay() .atZone(ZoneId.of("Asia/Seoul")) .withZoneSameInstant(ZoneId.of("UTC")) .toLocalDateTime() - val endDate = dateRange.endDate + var endDate = LocalDate.parse(endDateStr).atTime(LocalTime.MAX) .atZone(ZoneId.of("Asia/Seoul")) .withZoneSameInstant(ZoneId.of("UTC")) .toLocalDateTime() @@ -41,6 +41,16 @@ class AdminMemberStatisticsService(private val repository: AdminMemberStatistics val totalSignOutCount = repository.getTotalSignOutCount(startDate = startDate, endDate = endDate) val totalPaymentMemberCount = repository.getPaymentMemberCount(startDate = startDate, endDate = endDate) + startDate = dateRange.startDate + .atZone(ZoneId.of("Asia/Seoul")) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + + endDate = dateRange.endDate + .atZone(ZoneId.of("Asia/Seoul")) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + val signUpCountInRange = repository.getSignUpCountInRange( startDate = startDate, endDate = endDate, -- 2.40.1 From b817a230fd88f469989b331bdd47a627d9c81e35 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sat, 15 Mar 2025 00:46:26 +0900 Subject: [PATCH 4/6] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20-=20=EC=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A0=84=EC=B2=B4=20=ED=9A=8C=EC=9B=90=EC=88=98=20?= =?UTF-8?q?API=20-=20=EA=B2=B0=EC=A0=9C=EC=9E=90=20=EC=88=98=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=EC=9D=84=20=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=EC=B9=B4=EC=9A=B4=ED=8C=85=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../statistics/member/AdminMemberStatisticsRepository.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt index 3389986..055aa48 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt @@ -44,12 +44,12 @@ class AdminMemberStatisticsRepository(private val queryFactory: JPAQueryFactory) .select( QDateAndMemberCount( getFormattedDate(charge.createdAt), - member.id.countDistinct().castToNum(Int::class.java) + Expressions.numberTemplate(Int::class.java, "COUNT(DISTINCT {0})", member.id) ) ) .from(charge) .innerJoin(charge.member, member) - .leftJoin(charge.payment, payment) + .innerJoin(charge.payment, payment) .where( charge.status.eq(ChargeStatus.CHARGE), payment.status.eq(PaymentStatus.COMPLETE), @@ -119,12 +119,12 @@ class AdminMemberStatisticsRepository(private val queryFactory: JPAQueryFactory) .select( QDateAndMemberCount( getFormattedDate(charge.createdAt), - member.id.countDistinct().castToNum(Int::class.java) + Expressions.numberTemplate(Int::class.java, "COUNT(DISTINCT {0})", member.id) ) ) .from(charge) .innerJoin(charge.member, member) - .leftJoin(charge.payment, payment) + .innerJoin(charge.payment, payment) .where( charge.status.eq(ChargeStatus.CHARGE), payment.status.eq(PaymentStatus.COMPLETE), -- 2.40.1 From f65ddbc5b88305c96cc4cfe98be4c5634b56cbe2 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sat, 15 Mar 2025 00:54:17 +0900 Subject: [PATCH 5/6] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20-=20=EC=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A0=84=EC=B2=B4=20=ED=9A=8C=EC=9B=90=EC=88=98=20?= =?UTF-8?q?API=20-=20=EA=B2=B0=EC=A0=9C=EC=9E=90=20=EC=88=98=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=EC=9D=84=20=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=EC=B9=B4=EC=9A=B4=ED=8C=85=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/AdminMemberStatisticsRepository.kt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt index 055aa48..63159bc 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt @@ -44,7 +44,11 @@ class AdminMemberStatisticsRepository(private val queryFactory: JPAQueryFactory) .select( QDateAndMemberCount( getFormattedDate(charge.createdAt), - Expressions.numberTemplate(Int::class.java, "COUNT(DISTINCT {0})", member.id) + Expressions.numberTemplate( + Long::class.java, + "COUNT(DISTINCT {0})", + member.id + ).castToNum(Int::class.java) ) ) .from(charge) @@ -119,7 +123,11 @@ class AdminMemberStatisticsRepository(private val queryFactory: JPAQueryFactory) .select( QDateAndMemberCount( getFormattedDate(charge.createdAt), - Expressions.numberTemplate(Int::class.java, "COUNT(DISTINCT {0})", member.id) + Expressions.numberTemplate( + Long::class.java, + "COUNT(DISTINCT {0})", + member.id + ).castToNum(Int::class.java) ) ) .from(charge) -- 2.40.1 From 81fa4459647a9ca2d75d958750dd801150800fc9 Mon Sep 17 00:00:00 2001 From: Klaus Date: Sat, 15 Mar 2025 01:03:16 +0900 Subject: [PATCH 6/6] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20-=20=EC=9D=BC?= =?UTF-8?q?=EB=B3=84=20=EC=A0=84=EC=B2=B4=20=ED=9A=8C=EC=9B=90=EC=88=98=20?= =?UTF-8?q?API=20-=20=EA=B2=B0=EC=A0=9C=EC=9E=90=20=EC=88=98=20=EC=A4=91?= =?UTF-8?q?=EB=B3=B5=EC=9D=84=20=EC=A0=9C=EA=B1=B0=ED=95=98=EA=B3=A0=20?= =?UTF-8?q?=EC=B9=B4=EC=9A=B4=ED=8C=85=ED=95=98=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/AdminMemberStatisticsRepository.kt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt index 63159bc..25c69fc 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/statistics/member/AdminMemberStatisticsRepository.kt @@ -44,11 +44,7 @@ class AdminMemberStatisticsRepository(private val queryFactory: JPAQueryFactory) .select( QDateAndMemberCount( getFormattedDate(charge.createdAt), - Expressions.numberTemplate( - Long::class.java, - "COUNT(DISTINCT {0})", - member.id - ).castToNum(Int::class.java) + member.id.countDistinct().castToNum(Int::class.java) ) ) .from(charge) @@ -123,11 +119,7 @@ class AdminMemberStatisticsRepository(private val queryFactory: JPAQueryFactory) .select( QDateAndMemberCount( getFormattedDate(charge.createdAt), - Expressions.numberTemplate( - Long::class.java, - "COUNT(DISTINCT {0})", - member.id - ).castToNum(Int::class.java) + member.id.countDistinct().castToNum(Int::class.java) ) ) .from(charge) -- 2.40.1