마케팅

- 광고 통계 조회 API 추가
This commit is contained in:
Klaus 2025-03-05 21:49:33 +09:00
parent 0f68b297a0
commit 37516a0072
4 changed files with 190 additions and 0 deletions

View File

@ -0,0 +1,21 @@
package kr.co.vividnext.sodalive.admin.marketing.statistics
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.RestController
@RestController
@PreAuthorize("hasRole('ADMIN')")
@RequestMapping("/admin/marketing/statistics")
class AdminAdStatisticsController(private val service: AdminAdStatisticsService) {
@GetMapping
fun getStatistics(pageable: Pageable) = ApiResponse.ok(
service.getStatistics(
offset = pageable.offset,
limit = pageable.pageSize.toLong()
)
)
}

View File

@ -0,0 +1,129 @@
package kr.co.vividnext.sodalive.admin.marketing.statistics
import com.querydsl.core.types.dsl.CaseBuilder
import com.querydsl.core.types.dsl.DateTimePath
import com.querydsl.core.types.dsl.Expressions
import com.querydsl.core.types.dsl.NumberExpression
import com.querydsl.core.types.dsl.StringTemplate
import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.marketing.AdTrackingHistoryType
import kr.co.vividnext.sodalive.marketing.QAdTrackingHistory.adTrackingHistory
import org.springframework.stereotype.Repository
import java.time.LocalDateTime
@Repository
class AdminAdStatisticsRepository(private val queryFactory: JPAQueryFactory) {
fun getAdStatisticsDataTotalCount(): Int {
return queryFactory
.select(adTrackingHistory.id.pid)
.from(adTrackingHistory)
.groupBy(
getFormattedDate(adTrackingHistory.id.createdAt),
adTrackingHistory.mediaGroup,
adTrackingHistory.id.pid,
adTrackingHistory.pidName
)
.fetch()
.size
}
fun getAdStatisticsDataList(offset: Long, limit: Long): List<GetAdminAdStatisticsItem> {
val signUpCount = CaseBuilder()
.`when`(adTrackingHistory.id.type.eq(AdTrackingHistoryType.SIGNUP))
.then(1)
.otherwise(0)
.sum()
val firstPaymentCount = CaseBuilder()
.`when`(adTrackingHistory.id.type.eq(AdTrackingHistoryType.FIRST_PAYMENT))
.then(1)
.otherwise(0)
.sum()
val firstPaymentTotalAmount = CaseBuilder()
.`when`(adTrackingHistory.id.type.eq(AdTrackingHistoryType.FIRST_PAYMENT))
.then(adTrackingHistory.price)
.otherwise(Expressions.constant(0.0))
.sum()
val repeatPaymentCount = CaseBuilder()
.`when`(adTrackingHistory.id.type.eq(AdTrackingHistoryType.REPEAT_PAYMENT))
.then(1)
.otherwise(0)
.sum()
val repeatPaymentTotalAmount = CaseBuilder()
.`when`(adTrackingHistory.id.type.eq(AdTrackingHistoryType.REPEAT_PAYMENT))
.then(adTrackingHistory.price)
.otherwise(Expressions.constant(0.0))
.sum()
val allPaymentCount = CaseBuilder()
.`when`(
adTrackingHistory.id.type.eq(AdTrackingHistoryType.FIRST_PAYMENT)
.or(adTrackingHistory.id.type.eq(AdTrackingHistoryType.REPEAT_PAYMENT))
)
.then(1)
.otherwise(0)
.sum()
val allPaymentTotalAmount = CaseBuilder()
.`when`(
adTrackingHistory.id.type.eq(AdTrackingHistoryType.FIRST_PAYMENT)
.or(adTrackingHistory.id.type.eq(AdTrackingHistoryType.REPEAT_PAYMENT))
)
.then(adTrackingHistory.price)
.otherwise(Expressions.constant(0.0))
.sum()
return queryFactory
.select(
QGetAdminAdStatisticsItem(
getFormattedDate(adTrackingHistory.id.createdAt),
adTrackingHistory.mediaGroup,
adTrackingHistory.id.pid,
adTrackingHistory.pidName,
signUpCount,
firstPaymentCount,
roundedValueDecimalPlaces2(firstPaymentTotalAmount),
repeatPaymentCount,
roundedValueDecimalPlaces2(repeatPaymentTotalAmount),
allPaymentCount,
roundedValueDecimalPlaces2(allPaymentTotalAmount)
)
)
.from(adTrackingHistory)
.groupBy(
getFormattedDate(adTrackingHistory.id.createdAt),
adTrackingHistory.mediaGroup,
adTrackingHistory.id.pid,
adTrackingHistory.pidName
)
.offset(offset)
.limit(limit)
.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"
)
}
private fun roundedValueDecimalPlaces2(valueExpression: NumberExpression<Double>): NumberExpression<Double> {
return Expressions.numberTemplate(
Double::class.java,
"ROUND({0}, {1})",
valueExpression,
2
)
}
}

View File

@ -0,0 +1,18 @@
package kr.co.vividnext.sodalive.admin.marketing.statistics
import org.springframework.stereotype.Service
@Service
class AdminAdStatisticsService(
private val repository: AdminAdStatisticsRepository
) {
fun getStatistics(offset: Long, limit: Long): GetAdminAdStatisticsResponse {
val totalCount = repository.getAdStatisticsDataTotalCount()
val items = repository.getAdStatisticsDataList(offset, limit)
return GetAdminAdStatisticsResponse(
totalCount = totalCount,
items = items
)
}
}

View File

@ -0,0 +1,22 @@
package kr.co.vividnext.sodalive.admin.marketing.statistics
import com.querydsl.core.annotations.QueryProjection
data class GetAdminAdStatisticsResponse(
val totalCount: Int,
val items: List<GetAdminAdStatisticsItem>
)
data class GetAdminAdStatisticsItem @QueryProjection constructor(
val date: String,
val mediaGroup: String,
val pid: String,
val pidName: String,
val signUpCount: Int,
val firstPaymentCount: Int,
val firstPaymentTotalAmount: Double,
val repeatPaymentCount: Int,
val repeatPaymentTotalAmount: Double,
val allPaymentCount: Int,
val allPaymentTotalAmount: Double
)