feat(agent-read): 관리자 에이전트 조회 API를 추가한다
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
package kr.co.vividnext.sodalive.admin.partner.agent.read
|
||||
|
||||
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.PathVariable
|
||||
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/partner/agent")
|
||||
class AdminAgentReadController(
|
||||
private val service: AdminAgentReadService
|
||||
) {
|
||||
@GetMapping("/list")
|
||||
fun getAgentList(pageable: Pageable) = ApiResponse.ok(
|
||||
service.getAgentList(offset = pageable.offset, limit = pageable.pageSize.toLong())
|
||||
)
|
||||
|
||||
@GetMapping("/creator/search")
|
||||
fun searchAssignableCreators(
|
||||
@RequestParam(value = "search_word") searchWord: String,
|
||||
pageable: Pageable
|
||||
) = ApiResponse.ok(
|
||||
service.searchAssignableCreators(searchWord = searchWord, offset = pageable.offset, limit = pageable.pageSize.toLong())
|
||||
)
|
||||
|
||||
@GetMapping("/{agentId}/creator/list")
|
||||
fun getAssignedCreators(
|
||||
@PathVariable agentId: Long,
|
||||
pageable: Pageable
|
||||
) = ApiResponse.ok(
|
||||
service.getAssignedCreators(agentId = agentId, offset = pageable.offset, limit = pageable.pageSize.toLong())
|
||||
)
|
||||
|
||||
@GetMapping("/{agentId}/calculate/live-by-creator")
|
||||
fun getCalculateLiveByCreator(
|
||||
@PathVariable agentId: Long,
|
||||
@RequestParam startDateStr: String,
|
||||
@RequestParam endDateStr: String,
|
||||
pageable: Pageable
|
||||
) = ApiResponse.ok(
|
||||
service.getCalculateLiveByCreator(
|
||||
agentId,
|
||||
startDateStr,
|
||||
endDateStr,
|
||||
pageable.offset,
|
||||
pageable.pageSize.toLong()
|
||||
)
|
||||
)
|
||||
|
||||
@GetMapping("/{agentId}/calculate/content-by-creator")
|
||||
fun getCalculateContentByCreator(
|
||||
@PathVariable agentId: Long,
|
||||
@RequestParam startDateStr: String,
|
||||
@RequestParam endDateStr: String,
|
||||
pageable: Pageable
|
||||
) = ApiResponse.ok(
|
||||
service.getCalculateContentByCreator(
|
||||
agentId,
|
||||
startDateStr,
|
||||
endDateStr,
|
||||
pageable.offset,
|
||||
pageable.pageSize.toLong()
|
||||
)
|
||||
)
|
||||
|
||||
@GetMapping("/{agentId}/calculate/community-by-creator")
|
||||
fun getCalculateCommunityByCreator(
|
||||
@PathVariable agentId: Long,
|
||||
@RequestParam startDateStr: String,
|
||||
@RequestParam endDateStr: String,
|
||||
pageable: Pageable
|
||||
) = ApiResponse.ok(
|
||||
service.getCalculateCommunityByCreator(
|
||||
agentId,
|
||||
startDateStr,
|
||||
endDateStr,
|
||||
pageable.offset,
|
||||
pageable.pageSize.toLong()
|
||||
)
|
||||
)
|
||||
|
||||
@GetMapping("/{agentId}/calculate/channel-donation-by-creator")
|
||||
fun getChannelDonationByCreator(
|
||||
@PathVariable agentId: Long,
|
||||
@RequestParam startDateStr: String,
|
||||
@RequestParam endDateStr: String,
|
||||
pageable: Pageable
|
||||
) = ApiResponse.ok(
|
||||
service.getChannelDonationByCreator(
|
||||
agentId,
|
||||
startDateStr,
|
||||
endDateStr,
|
||||
pageable.offset,
|
||||
pageable.pageSize.toLong()
|
||||
)
|
||||
)
|
||||
|
||||
@GetMapping("/{agentId}/calculate/content-donation-by-creator")
|
||||
fun getCalculateContentDonationByCreator(
|
||||
@PathVariable agentId: Long,
|
||||
@RequestParam startDateStr: String,
|
||||
@RequestParam endDateStr: String,
|
||||
pageable: Pageable
|
||||
) = ApiResponse.ok(
|
||||
service.getCalculateContentDonationByCreator(
|
||||
agentId,
|
||||
startDateStr,
|
||||
endDateStr,
|
||||
pageable.offset,
|
||||
pageable.pageSize.toLong()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package kr.co.vividnext.sodalive.admin.partner.agent.read
|
||||
|
||||
import com.querydsl.core.types.dsl.BooleanExpression
|
||||
import com.querydsl.core.types.dsl.Expressions
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.member.QMember
|
||||
import kr.co.vividnext.sodalive.member.QMember.member
|
||||
import kr.co.vividnext.sodalive.partner.agent.assignment.QAgentCreatorRelation.agentCreatorRelation
|
||||
import kr.co.vividnext.sodalive.partner.agent.calculate.AgentCalculateQueryRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
@Repository
|
||||
class AdminAgentReadQueryRepository(
|
||||
private val queryFactory: JPAQueryFactory,
|
||||
private val calculateQueryRepository: AgentCalculateQueryRepository
|
||||
) {
|
||||
private val kstZoneId = ZoneId.of("Asia/Seoul")
|
||||
private val utcZoneId = ZoneId.of("UTC")
|
||||
|
||||
fun getAgentListTotalCount(): Int {
|
||||
return queryFactory
|
||||
.select(member.id.count())
|
||||
.from(member)
|
||||
.where(member.role.eq(MemberRole.AGENT))
|
||||
.fetchOne()
|
||||
?.toInt()
|
||||
?: 0
|
||||
}
|
||||
|
||||
fun getAgentList(offset: Long, limit: Long, currentTime: ZonedDateTime): List<GetAdminAgentListItem> {
|
||||
val kstCurrentTime = currentTime.withZoneSameInstant(kstZoneId)
|
||||
val currentMonthStartKst = kstCurrentTime.toLocalDate().withDayOfMonth(1).atStartOfDay(kstZoneId)
|
||||
val nextMonthStartKst = currentMonthStartKst.plusMonths(1)
|
||||
val currentMonthStart = currentMonthStartKst.withZoneSameInstant(utcZoneId).toLocalDateTime()
|
||||
val currentMonthEnd = nextMonthStartKst.withZoneSameInstant(utcZoneId).toLocalDateTime().minusNanos(1)
|
||||
|
||||
return queryFactory
|
||||
.select(
|
||||
QGetAdminAgentListItem(
|
||||
member.id,
|
||||
member.nickname,
|
||||
agentCreatorRelation.id.countDistinct().intValue(),
|
||||
Expressions.numberTemplate(Int::class.java, "0"),
|
||||
Expressions.numberTemplate(Int::class.java, "0"),
|
||||
Expressions.numberTemplate(Int::class.java, "0"),
|
||||
Expressions.numberTemplate(Int::class.java, "0"),
|
||||
Expressions.numberTemplate(Int::class.java, "0")
|
||||
)
|
||||
)
|
||||
.from(member)
|
||||
.leftJoin(agentCreatorRelation)
|
||||
.on(
|
||||
agentCreatorRelation.agent.id.eq(member.id)
|
||||
.and(isActiveAssignment(kstCurrentTime.toLocalDateTime()))
|
||||
)
|
||||
.where(member.role.eq(MemberRole.AGENT))
|
||||
.groupBy(member.id, member.nickname)
|
||||
.orderBy(member.id.desc())
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
.fetch()
|
||||
.map { item ->
|
||||
item.copy(
|
||||
liveAgentSettlementAmount = calculateQueryRepository
|
||||
.getCalculateLiveByCreatorTotal(currentMonthStart, currentMonthEnd, item.agentId)
|
||||
.agentSettlementAmount,
|
||||
contentAgentSettlementAmount = calculateQueryRepository
|
||||
.getCalculateContentByCreatorTotal(currentMonthStart, currentMonthEnd, item.agentId)
|
||||
.agentSettlementAmount,
|
||||
communityAgentSettlementAmount = calculateQueryRepository
|
||||
.getCalculateCommunityByCreatorTotal(currentMonthStart, currentMonthEnd, item.agentId)
|
||||
.agentSettlementAmount,
|
||||
contentDonationAgentSettlementAmount = calculateQueryRepository
|
||||
.getCalculateContentDonationByCreatorTotal(currentMonthStart, currentMonthEnd, item.agentId)
|
||||
.agentSettlementAmount,
|
||||
channelDonationAgentSettlementAmount = calculateQueryRepository
|
||||
.getChannelDonationByCreatorTotal(currentMonthStart, currentMonthEnd, item.agentId)
|
||||
.agentSettlementAmount
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun searchAssignableCreatorsTotalCount(searchWord: String, currentTime: LocalDateTime): Int {
|
||||
return queryFactory
|
||||
.select(member.id.countDistinct())
|
||||
.from(member)
|
||||
.leftJoin(agentCreatorRelation)
|
||||
.on(
|
||||
agentCreatorRelation.creator.id.eq(member.id)
|
||||
.and(isActiveAssignment(currentTime))
|
||||
)
|
||||
.where(
|
||||
member.role.eq(MemberRole.CREATOR)
|
||||
.and(member.nickname.contains(searchWord))
|
||||
)
|
||||
.fetchOne()
|
||||
?.toInt()
|
||||
?: 0
|
||||
}
|
||||
|
||||
fun searchAssignableCreators(
|
||||
searchWord: String,
|
||||
offset: Long,
|
||||
limit: Long,
|
||||
currentTime: LocalDateTime
|
||||
): List<SearchAdminAgentAssignableCreatorItem> {
|
||||
val currentAgent = QMember("currentAgent")
|
||||
|
||||
return queryFactory
|
||||
.select(
|
||||
QSearchAdminAgentAssignableCreatorItem(
|
||||
member.id,
|
||||
member.nickname,
|
||||
currentAgent.id,
|
||||
currentAgent.nickname
|
||||
)
|
||||
)
|
||||
.from(member)
|
||||
.leftJoin(agentCreatorRelation)
|
||||
.on(
|
||||
agentCreatorRelation.creator.id.eq(member.id)
|
||||
.and(isActiveAssignment(currentTime))
|
||||
)
|
||||
.leftJoin(agentCreatorRelation.agent, currentAgent)
|
||||
.where(
|
||||
member.role.eq(MemberRole.CREATOR)
|
||||
.and(member.nickname.contains(searchWord))
|
||||
)
|
||||
.orderBy(member.id.desc())
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
.fetch()
|
||||
}
|
||||
|
||||
fun getAssignedCreatorTotalCount(agentId: Long, currentTime: LocalDateTime): Int {
|
||||
return queryFactory
|
||||
.select(agentCreatorRelation.id.count())
|
||||
.from(agentCreatorRelation)
|
||||
.where(agentCreatorRelation.agent.id.eq(agentId).and(isActiveAssignment(currentTime)))
|
||||
.fetchOne()
|
||||
?.toInt()
|
||||
?: 0
|
||||
}
|
||||
|
||||
fun getAssignedCreators(
|
||||
agentId: Long,
|
||||
offset: Long,
|
||||
limit: Long,
|
||||
currentTime: LocalDateTime
|
||||
): List<GetAdminAgentAssignedCreatorItem> {
|
||||
return queryFactory
|
||||
.select(
|
||||
QGetAdminAgentAssignedCreatorItem(
|
||||
agentCreatorRelation.creator.id,
|
||||
agentCreatorRelation.creator.nickname,
|
||||
agentCreatorRelation.assignedAt
|
||||
)
|
||||
)
|
||||
.from(agentCreatorRelation)
|
||||
.where(agentCreatorRelation.agent.id.eq(agentId).and(isActiveAssignment(currentTime)))
|
||||
.orderBy(agentCreatorRelation.creator.id.desc())
|
||||
.offset(offset)
|
||||
.limit(limit)
|
||||
.fetch()
|
||||
}
|
||||
|
||||
private fun isActiveAssignment(currentTime: LocalDateTime): BooleanExpression {
|
||||
return agentCreatorRelation.assignedAt.loe(currentTime)
|
||||
.and(agentCreatorRelation.unassignedAt.isNull.or(agentCreatorRelation.unassignedAt.gt(currentTime)))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
package kr.co.vividnext.sodalive.admin.partner.agent.read
|
||||
|
||||
import kr.co.vividnext.sodalive.common.SodaException
|
||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||
import kr.co.vividnext.sodalive.member.MemberRole
|
||||
import kr.co.vividnext.sodalive.partner.agent.calculate.AgentCalculateService
|
||||
import kr.co.vividnext.sodalive.partner.agent.calculate.GetAgentChannelDonationSettlementByCreatorResponse
|
||||
import kr.co.vividnext.sodalive.partner.agent.calculate.GetAgentSettlementByCreatorResponse
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneId
|
||||
import java.time.ZonedDateTime
|
||||
|
||||
@Service
|
||||
class AdminAgentReadService(
|
||||
private val queryRepository: AdminAgentReadQueryRepository,
|
||||
private val memberRepository: MemberRepository,
|
||||
private val calculateService: AgentCalculateService
|
||||
) {
|
||||
private val kstZoneId = ZoneId.of("Asia/Seoul")
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getAgentList(offset: Long, limit: Long): GetAdminAgentListResponse {
|
||||
val now = ZonedDateTime.now(kstZoneId)
|
||||
return GetAdminAgentListResponse(
|
||||
totalCount = queryRepository.getAgentListTotalCount(),
|
||||
items = queryRepository.getAgentList(offset = offset, limit = limit, currentTime = now)
|
||||
)
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun searchAssignableCreators(searchWord: String, offset: Long, limit: Long): SearchAdminAgentAssignableCreatorResponse {
|
||||
if (searchWord.length < 2) throw SodaException(messageKey = "admin.member.search_word_min_length")
|
||||
val now = LocalDateTime.now()
|
||||
return SearchAdminAgentAssignableCreatorResponse(
|
||||
totalCount = queryRepository.searchAssignableCreatorsTotalCount(searchWord = searchWord, currentTime = now),
|
||||
items = queryRepository.searchAssignableCreators(
|
||||
searchWord = searchWord,
|
||||
offset = offset,
|
||||
limit = limit,
|
||||
currentTime = now
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getAssignedCreators(agentId: Long, offset: Long, limit: Long): GetAdminAgentAssignedCreatorResponse {
|
||||
validateAgent(agentId)
|
||||
val now = LocalDateTime.now()
|
||||
return GetAdminAgentAssignedCreatorResponse(
|
||||
totalCount = queryRepository.getAssignedCreatorTotalCount(agentId = agentId, currentTime = now),
|
||||
items = queryRepository.getAssignedCreators(agentId = agentId, offset = offset, limit = limit, currentTime = now)
|
||||
)
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getCalculateLiveByCreator(
|
||||
agentId: Long,
|
||||
startDateStr: String,
|
||||
endDateStr: String,
|
||||
offset: Long,
|
||||
limit: Long
|
||||
): GetAgentSettlementByCreatorResponse {
|
||||
validateAgent(agentId)
|
||||
return calculateService.getCalculateLiveByCreator(startDateStr, endDateStr, agentId, offset, limit)
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getCalculateContentByCreator(
|
||||
agentId: Long,
|
||||
startDateStr: String,
|
||||
endDateStr: String,
|
||||
offset: Long,
|
||||
limit: Long
|
||||
): GetAgentSettlementByCreatorResponse {
|
||||
validateAgent(agentId)
|
||||
return calculateService.getCalculateContentByCreator(startDateStr, endDateStr, agentId, offset, limit)
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getCalculateCommunityByCreator(
|
||||
agentId: Long,
|
||||
startDateStr: String,
|
||||
endDateStr: String,
|
||||
offset: Long,
|
||||
limit: Long
|
||||
): GetAgentSettlementByCreatorResponse {
|
||||
validateAgent(agentId)
|
||||
return calculateService.getCalculateCommunityByCreator(startDateStr, endDateStr, agentId, offset, limit)
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getCalculateContentDonationByCreator(
|
||||
agentId: Long,
|
||||
startDateStr: String,
|
||||
endDateStr: String,
|
||||
offset: Long,
|
||||
limit: Long
|
||||
): GetAgentSettlementByCreatorResponse {
|
||||
validateAgent(agentId)
|
||||
return calculateService.getCalculateContentDonationByCreator(startDateStr, endDateStr, agentId, offset, limit)
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun getChannelDonationByCreator(
|
||||
agentId: Long,
|
||||
startDateStr: String,
|
||||
endDateStr: String,
|
||||
offset: Long,
|
||||
limit: Long
|
||||
): GetAgentChannelDonationSettlementByCreatorResponse {
|
||||
validateAgent(agentId)
|
||||
return calculateService.getChannelDonationByCreator(startDateStr, endDateStr, agentId, offset, limit)
|
||||
}
|
||||
|
||||
private fun validateAgent(agentId: Long) {
|
||||
val member = memberRepository.findById(agentId).orElseThrow {
|
||||
SodaException(messageKey = "partner.agent.ratio.agent_not_found")
|
||||
}
|
||||
|
||||
if (member.role != MemberRole.AGENT) {
|
||||
throw SodaException(messageKey = "partner.agent.ratio.invalid_agent")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package kr.co.vividnext.sodalive.admin.partner.agent.read
|
||||
|
||||
import com.querydsl.core.annotations.QueryProjection
|
||||
import java.time.LocalDateTime
|
||||
|
||||
data class GetAdminAgentAssignedCreatorResponse(
|
||||
val totalCount: Int,
|
||||
val items: List<GetAdminAgentAssignedCreatorItem>
|
||||
)
|
||||
|
||||
data class GetAdminAgentAssignedCreatorItem @QueryProjection constructor(
|
||||
val creatorId: Long,
|
||||
val creatorNickname: String,
|
||||
val assignedAt: LocalDateTime
|
||||
)
|
||||
@@ -0,0 +1,19 @@
|
||||
package kr.co.vividnext.sodalive.admin.partner.agent.read
|
||||
|
||||
import com.querydsl.core.annotations.QueryProjection
|
||||
|
||||
data class GetAdminAgentListResponse(
|
||||
val totalCount: Int,
|
||||
val items: List<GetAdminAgentListItem>
|
||||
)
|
||||
|
||||
data class GetAdminAgentListItem @QueryProjection constructor(
|
||||
val agentId: Long,
|
||||
val agentNickname: String,
|
||||
val assignedCreatorCount: Int,
|
||||
val liveAgentSettlementAmount: Int = 0,
|
||||
val contentAgentSettlementAmount: Int = 0,
|
||||
val communityAgentSettlementAmount: Int = 0,
|
||||
val contentDonationAgentSettlementAmount: Int = 0,
|
||||
val channelDonationAgentSettlementAmount: Int = 0
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
package kr.co.vividnext.sodalive.admin.partner.agent.read
|
||||
|
||||
import com.querydsl.core.annotations.QueryProjection
|
||||
|
||||
data class SearchAdminAgentAssignableCreatorResponse(
|
||||
val totalCount: Int,
|
||||
val items: List<SearchAdminAgentAssignableCreatorItem>
|
||||
)
|
||||
|
||||
data class SearchAdminAgentAssignableCreatorItem @QueryProjection constructor(
|
||||
val creatorId: Long,
|
||||
val creatorNickname: String,
|
||||
val currentAgentId: Long?,
|
||||
val currentAgentNickname: String?
|
||||
)
|
||||
Reference in New Issue
Block a user