fix(agent-ratio): 정산 비율 목록을 current history 구조로 정리한다
This commit is contained in:
@@ -7,6 +7,7 @@ import kr.co.vividnext.sodalive.partner.agent.ratio.AgentSettlementRatio
|
|||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.AgentSettlementRatioRepository
|
import kr.co.vividnext.sodalive.partner.agent.ratio.AgentSettlementRatioRepository
|
||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.CreateAgentSettlementRatioRequest
|
import kr.co.vividnext.sodalive.partner.agent.ratio.CreateAgentSettlementRatioRequest
|
||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioResponse
|
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioResponse
|
||||||
|
import kr.co.vividnext.sodalive.partner.agent.ratio.toGroupedResponseItems
|
||||||
import org.springframework.dao.DataIntegrityViolationException
|
import org.springframework.dao.DataIntegrityViolationException
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.transaction.annotation.Transactional
|
import org.springframework.transaction.annotation.Transactional
|
||||||
@@ -49,6 +50,7 @@ class AdminAgentSettlementRatioService(
|
|||||||
fun getAgentSettlementRatio(offset: Long, limit: Long): GetAgentSettlementRatioResponse {
|
fun getAgentSettlementRatio(offset: Long, limit: Long): GetAgentSettlementRatioResponse {
|
||||||
val totalCount = repository.getAgentSettlementRatioTotalCount()
|
val totalCount = repository.getAgentSettlementRatioTotalCount()
|
||||||
val items = repository.getAgentSettlementRatio(offset = offset, limit = limit)
|
val items = repository.getAgentSettlementRatio(offset = offset, limit = limit)
|
||||||
|
.toGroupedResponseItems()
|
||||||
return GetAgentSettlementRatioResponse(totalCount = totalCount, items = items)
|
return GetAgentSettlementRatioResponse(totalCount = totalCount, items = items)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,17 +13,31 @@ interface AgentSettlementRatioRepository :
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface AgentSettlementRatioQueryRepository {
|
interface AgentSettlementRatioQueryRepository {
|
||||||
fun getAgentSettlementRatio(offset: Long, limit: Long): List<GetAgentSettlementRatioItem>
|
fun getAgentSettlementRatio(offset: Long, limit: Long): List<GetAgentSettlementRatioRow>
|
||||||
fun getAgentSettlementRatioTotalCount(): Int
|
fun getAgentSettlementRatioTotalCount(): Int
|
||||||
}
|
}
|
||||||
|
|
||||||
class AgentSettlementRatioQueryRepositoryImpl(
|
class AgentSettlementRatioQueryRepositoryImpl(
|
||||||
private val queryFactory: JPAQueryFactory
|
private val queryFactory: JPAQueryFactory
|
||||||
) : AgentSettlementRatioQueryRepository {
|
) : AgentSettlementRatioQueryRepository {
|
||||||
override fun getAgentSettlementRatio(offset: Long, limit: Long): List<GetAgentSettlementRatioItem> {
|
override fun getAgentSettlementRatio(offset: Long, limit: Long): List<GetAgentSettlementRatioRow> {
|
||||||
|
val memberIds = queryFactory
|
||||||
|
.select(member.id)
|
||||||
|
.from(agentSettlementRatio)
|
||||||
|
.innerJoin(agentSettlementRatio.member, member)
|
||||||
|
.groupBy(member.id)
|
||||||
|
.orderBy(member.id.desc())
|
||||||
|
.offset(offset)
|
||||||
|
.limit(limit)
|
||||||
|
.fetch()
|
||||||
|
|
||||||
|
if (memberIds.isEmpty()) {
|
||||||
|
return emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
return queryFactory
|
return queryFactory
|
||||||
.select(
|
.select(
|
||||||
QGetAgentSettlementRatioItem(
|
QGetAgentSettlementRatioRow(
|
||||||
member.id,
|
member.id,
|
||||||
member.nickname,
|
member.nickname,
|
||||||
agentSettlementRatio.settlementRatio,
|
agentSettlementRatio.settlementRatio,
|
||||||
@@ -33,16 +47,16 @@ class AgentSettlementRatioQueryRepositoryImpl(
|
|||||||
)
|
)
|
||||||
.from(agentSettlementRatio)
|
.from(agentSettlementRatio)
|
||||||
.innerJoin(agentSettlementRatio.member, member)
|
.innerJoin(agentSettlementRatio.member, member)
|
||||||
.orderBy(agentSettlementRatio.id.asc())
|
.where(member.id.`in`(memberIds))
|
||||||
.offset(offset)
|
.orderBy(member.id.desc(), agentSettlementRatio.effectiveFrom.desc())
|
||||||
.limit(limit)
|
|
||||||
.fetch()
|
.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAgentSettlementRatioTotalCount(): Int {
|
override fun getAgentSettlementRatioTotalCount(): Int {
|
||||||
return queryFactory
|
return queryFactory
|
||||||
.select(agentSettlementRatio.id.count())
|
.select(member.id.countDistinct())
|
||||||
.from(agentSettlementRatio)
|
.from(agentSettlementRatio)
|
||||||
|
.innerJoin(agentSettlementRatio.member, member)
|
||||||
.fetchOne()
|
.fetchOne()
|
||||||
?.toInt()
|
?.toInt()
|
||||||
?: 0
|
?: 0
|
||||||
|
|||||||
@@ -8,10 +8,41 @@ data class GetAgentSettlementRatioResponse(
|
|||||||
val items: List<GetAgentSettlementRatioItem>
|
val items: List<GetAgentSettlementRatioItem>
|
||||||
)
|
)
|
||||||
|
|
||||||
data class GetAgentSettlementRatioItem @QueryProjection constructor(
|
data class GetAgentSettlementRatioItem(
|
||||||
|
val memberId: Long,
|
||||||
|
val nickname: String,
|
||||||
|
val current: GetAgentSettlementRatioHistoryItem?,
|
||||||
|
val history: List<GetAgentSettlementRatioHistoryItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GetAgentSettlementRatioHistoryItem(
|
||||||
|
val settlementRatio: Int,
|
||||||
|
val effectiveFrom: LocalDateTime,
|
||||||
|
val effectiveTo: LocalDateTime?
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GetAgentSettlementRatioRow @QueryProjection constructor(
|
||||||
val memberId: Long,
|
val memberId: Long,
|
||||||
val nickname: String,
|
val nickname: String,
|
||||||
val settlementRatio: Int,
|
val settlementRatio: Int,
|
||||||
val effectiveFrom: LocalDateTime,
|
val effectiveFrom: LocalDateTime,
|
||||||
val effectiveTo: LocalDateTime?
|
val effectiveTo: LocalDateTime?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fun List<GetAgentSettlementRatioRow>.toGroupedResponseItems(): List<GetAgentSettlementRatioItem> {
|
||||||
|
return groupBy { it.memberId to it.nickname }
|
||||||
|
.map { (memberInfo, rows) ->
|
||||||
|
GetAgentSettlementRatioItem(
|
||||||
|
memberId = memberInfo.first,
|
||||||
|
nickname = memberInfo.second,
|
||||||
|
current = rows.firstOrNull { it.effectiveTo == null }?.toHistoryItem(),
|
||||||
|
history = rows.filter { it.effectiveTo != null }.map { it.toHistoryItem() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun GetAgentSettlementRatioRow.toHistoryItem() = GetAgentSettlementRatioHistoryItem(
|
||||||
|
settlementRatio = settlementRatio,
|
||||||
|
effectiveFrom = effectiveFrom,
|
||||||
|
effectiveTo = effectiveTo
|
||||||
|
)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package kr.co.vividnext.sodalive.admin.partner.agent.ratio
|
package kr.co.vividnext.sodalive.admin.partner.agent.ratio
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.CreateAgentSettlementRatioRequest
|
import kr.co.vividnext.sodalive.partner.agent.ratio.CreateAgentSettlementRatioRequest
|
||||||
|
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioHistoryItem
|
||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioItem
|
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioItem
|
||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioResponse
|
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioResponse
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
@@ -60,9 +61,18 @@ class AdminAgentSettlementRatioControllerTest {
|
|||||||
GetAgentSettlementRatioItem(
|
GetAgentSettlementRatioItem(
|
||||||
memberId = 31L,
|
memberId = 31L,
|
||||||
nickname = "agent-a",
|
nickname = "agent-a",
|
||||||
settlementRatio = 15,
|
current = GetAgentSettlementRatioHistoryItem(
|
||||||
effectiveFrom = LocalDateTime.of(2026, 4, 9, 10, 0),
|
settlementRatio = 15,
|
||||||
effectiveTo = null
|
effectiveFrom = LocalDateTime.of(2026, 4, 9, 10, 0),
|
||||||
|
effectiveTo = null
|
||||||
|
),
|
||||||
|
history = listOf(
|
||||||
|
GetAgentSettlementRatioHistoryItem(
|
||||||
|
settlementRatio = 10,
|
||||||
|
effectiveFrom = LocalDateTime.of(2026, 4, 1, 0, 0),
|
||||||
|
effectiveTo = LocalDateTime.of(2026, 4, 9, 10, 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@@ -73,9 +83,10 @@ class AdminAgentSettlementRatioControllerTest {
|
|||||||
|
|
||||||
assertEquals(true, response.success)
|
assertEquals(true, response.success)
|
||||||
assertEquals(1, response.data!!.totalCount)
|
assertEquals(1, response.data!!.totalCount)
|
||||||
assertEquals(15, response.data!!.items[0].settlementRatio)
|
assertEquals(15, response.data!!.items[0].current!!.settlementRatio)
|
||||||
assertEquals(LocalDateTime.of(2026, 4, 9, 10, 0), response.data!!.items[0].effectiveFrom)
|
assertEquals(LocalDateTime.of(2026, 4, 9, 10, 0), response.data!!.items[0].current!!.effectiveFrom)
|
||||||
assertEquals(null, response.data!!.items[0].effectiveTo)
|
assertEquals(null, response.data!!.items[0].current!!.effectiveTo)
|
||||||
|
assertEquals(1, response.data!!.items[0].history.size)
|
||||||
Mockito.verify(service).getAgentSettlementRatio(offset = 20L, limit = 20L)
|
Mockito.verify(service).getAgentSettlementRatio(offset = 20L, limit = 20L)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import kr.co.vividnext.sodalive.member.MemberRole
|
|||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.AgentSettlementRatio
|
import kr.co.vividnext.sodalive.partner.agent.ratio.AgentSettlementRatio
|
||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.AgentSettlementRatioRepository
|
import kr.co.vividnext.sodalive.partner.agent.ratio.AgentSettlementRatioRepository
|
||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.CreateAgentSettlementRatioRequest
|
import kr.co.vividnext.sodalive.partner.agent.ratio.CreateAgentSettlementRatioRequest
|
||||||
|
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioHistoryItem
|
||||||
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioItem
|
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioItem
|
||||||
|
import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioRow
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
import org.junit.jupiter.api.Assertions.assertThrows
|
import org.junit.jupiter.api.Assertions.assertThrows
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
@@ -345,24 +347,67 @@ class AgentSettlementRatioServiceTest {
|
|||||||
@DisplayName("관리자는 에이전트 정산 비율 목록을 조회할 수 있다")
|
@DisplayName("관리자는 에이전트 정산 비율 목록을 조회할 수 있다")
|
||||||
fun shouldGetAgentSettlementRatioList() {
|
fun shouldGetAgentSettlementRatioList() {
|
||||||
val items = listOf(
|
val items = listOf(
|
||||||
GetAgentSettlementRatioItem(
|
GetAgentSettlementRatioRow(
|
||||||
memberId = 31L,
|
memberId = 31L,
|
||||||
nickname = "agent-a",
|
nickname = "agent-a",
|
||||||
settlementRatio = 15,
|
settlementRatio = 15,
|
||||||
effectiveFrom = LocalDateTime.of(2026, 4, 9, 10, 0),
|
effectiveFrom = LocalDateTime.of(2026, 4, 9, 10, 0),
|
||||||
effectiveTo = null
|
effectiveTo = null
|
||||||
|
),
|
||||||
|
GetAgentSettlementRatioRow(
|
||||||
|
memberId = 31L,
|
||||||
|
nickname = "agent-a",
|
||||||
|
settlementRatio = 10,
|
||||||
|
effectiveFrom = LocalDateTime.of(2026, 4, 1, 0, 0),
|
||||||
|
effectiveTo = LocalDateTime.of(2026, 4, 9, 10, 0)
|
||||||
|
),
|
||||||
|
GetAgentSettlementRatioRow(
|
||||||
|
memberId = 21L,
|
||||||
|
nickname = "agent-b",
|
||||||
|
settlementRatio = 12,
|
||||||
|
effectiveFrom = LocalDateTime.of(2026, 3, 1, 0, 0),
|
||||||
|
effectiveTo = LocalDateTime.of(2026, 3, 15, 0, 0)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
Mockito.`when`(repository.getAgentSettlementRatioTotalCount()).thenReturn(1)
|
Mockito.`when`(repository.getAgentSettlementRatioTotalCount()).thenReturn(2)
|
||||||
Mockito.`when`(repository.getAgentSettlementRatio(offset = 20L, limit = 20L)).thenReturn(items)
|
Mockito.`when`(repository.getAgentSettlementRatio(offset = 20L, limit = 20L)).thenReturn(items)
|
||||||
|
|
||||||
val response = service.getAgentSettlementRatio(offset = 20L, limit = 20L)
|
val response = service.getAgentSettlementRatio(offset = 20L, limit = 20L)
|
||||||
|
|
||||||
assertEquals(1, response.totalCount)
|
assertEquals(2, response.totalCount)
|
||||||
assertEquals(1, response.items.size)
|
assertEquals(2, response.items.size)
|
||||||
assertEquals(15, response.items[0].settlementRatio)
|
assertEquals(
|
||||||
assertEquals(LocalDateTime.of(2026, 4, 9, 10, 0), response.items[0].effectiveFrom)
|
GetAgentSettlementRatioItem(
|
||||||
assertEquals(null, response.items[0].effectiveTo)
|
memberId = 31L,
|
||||||
|
nickname = "agent-a",
|
||||||
|
current = GetAgentSettlementRatioHistoryItem(
|
||||||
|
settlementRatio = 15,
|
||||||
|
effectiveFrom = LocalDateTime.of(2026, 4, 9, 10, 0),
|
||||||
|
effectiveTo = null
|
||||||
|
),
|
||||||
|
history = listOf(
|
||||||
|
GetAgentSettlementRatioHistoryItem(
|
||||||
|
settlementRatio = 10,
|
||||||
|
effectiveFrom = LocalDateTime.of(2026, 4, 1, 0, 0),
|
||||||
|
effectiveTo = LocalDateTime.of(2026, 4, 9, 10, 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
response.items[0]
|
||||||
|
)
|
||||||
|
assertEquals(21L, response.items[1].memberId)
|
||||||
|
assertEquals("agent-b", response.items[1].nickname)
|
||||||
|
assertEquals(null, response.items[1].current)
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
GetAgentSettlementRatioHistoryItem(
|
||||||
|
settlementRatio = 12,
|
||||||
|
effectiveFrom = LocalDateTime.of(2026, 3, 1, 0, 0),
|
||||||
|
effectiveTo = LocalDateTime.of(2026, 3, 15, 0, 0)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
response.items[1].history
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user