From 53f37b93fbdbbf58fc0ea5614a8543348f542210 Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 10 Apr 2026 13:50:35 +0900 Subject: [PATCH] =?UTF-8?q?fix(agent-ratio):=20=EC=A0=95=EC=82=B0=20?= =?UTF-8?q?=EB=B9=84=EC=9C=A8=20=EB=AA=A9=EB=A1=9D=EC=9D=84=20current=20hi?= =?UTF-8?q?story=20=EA=B5=AC=EC=A1=B0=EB=A1=9C=20=EC=A0=95=EB=A6=AC?= =?UTF-8?q?=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ratio/AdminAgentSettlementRatioService.kt | 2 + .../ratio/AgentSettlementRatioRepository.kt | 28 ++++++--- .../ratio/GetAgentSettlementRatioResponse.kt | 33 ++++++++++- ...AdminAgentSettlementRatioControllerTest.kt | 23 ++++++-- .../ratio/AgentSettlementRatioServiceTest.kt | 59 ++++++++++++++++--- 5 files changed, 124 insertions(+), 21 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AdminAgentSettlementRatioService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AdminAgentSettlementRatioService.kt index a341437b..a035ee3b 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AdminAgentSettlementRatioService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AdminAgentSettlementRatioService.kt @@ -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.CreateAgentSettlementRatioRequest 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.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -49,6 +50,7 @@ class AdminAgentSettlementRatioService( fun getAgentSettlementRatio(offset: Long, limit: Long): GetAgentSettlementRatioResponse { val totalCount = repository.getAgentSettlementRatioTotalCount() val items = repository.getAgentSettlementRatio(offset = offset, limit = limit) + .toGroupedResponseItems() return GetAgentSettlementRatioResponse(totalCount = totalCount, items = items) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/partner/agent/ratio/AgentSettlementRatioRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/partner/agent/ratio/AgentSettlementRatioRepository.kt index ea7fa08e..55a7ca87 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/partner/agent/ratio/AgentSettlementRatioRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/partner/agent/ratio/AgentSettlementRatioRepository.kt @@ -13,17 +13,31 @@ interface AgentSettlementRatioRepository : } interface AgentSettlementRatioQueryRepository { - fun getAgentSettlementRatio(offset: Long, limit: Long): List + fun getAgentSettlementRatio(offset: Long, limit: Long): List fun getAgentSettlementRatioTotalCount(): Int } class AgentSettlementRatioQueryRepositoryImpl( private val queryFactory: JPAQueryFactory ) : AgentSettlementRatioQueryRepository { - override fun getAgentSettlementRatio(offset: Long, limit: Long): List { + override fun getAgentSettlementRatio(offset: Long, limit: Long): List { + 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 .select( - QGetAgentSettlementRatioItem( + QGetAgentSettlementRatioRow( member.id, member.nickname, agentSettlementRatio.settlementRatio, @@ -33,16 +47,16 @@ class AgentSettlementRatioQueryRepositoryImpl( ) .from(agentSettlementRatio) .innerJoin(agentSettlementRatio.member, member) - .orderBy(agentSettlementRatio.id.asc()) - .offset(offset) - .limit(limit) + .where(member.id.`in`(memberIds)) + .orderBy(member.id.desc(), agentSettlementRatio.effectiveFrom.desc()) .fetch() } override fun getAgentSettlementRatioTotalCount(): Int { return queryFactory - .select(agentSettlementRatio.id.count()) + .select(member.id.countDistinct()) .from(agentSettlementRatio) + .innerJoin(agentSettlementRatio.member, member) .fetchOne() ?.toInt() ?: 0 diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/partner/agent/ratio/GetAgentSettlementRatioResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/partner/agent/ratio/GetAgentSettlementRatioResponse.kt index b982bf48..35a92701 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/partner/agent/ratio/GetAgentSettlementRatioResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/partner/agent/ratio/GetAgentSettlementRatioResponse.kt @@ -8,10 +8,41 @@ data class GetAgentSettlementRatioResponse( val items: List ) -data class GetAgentSettlementRatioItem @QueryProjection constructor( +data class GetAgentSettlementRatioItem( + val memberId: Long, + val nickname: String, + val current: GetAgentSettlementRatioHistoryItem?, + val history: List +) + +data class GetAgentSettlementRatioHistoryItem( + val settlementRatio: Int, + val effectiveFrom: LocalDateTime, + val effectiveTo: LocalDateTime? +) + +data class GetAgentSettlementRatioRow @QueryProjection constructor( val memberId: Long, val nickname: String, val settlementRatio: Int, val effectiveFrom: LocalDateTime, val effectiveTo: LocalDateTime? ) + +fun List.toGroupedResponseItems(): List { + 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 +) diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AdminAgentSettlementRatioControllerTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AdminAgentSettlementRatioControllerTest.kt index 561fc296..0712b1fc 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AdminAgentSettlementRatioControllerTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AdminAgentSettlementRatioControllerTest.kt @@ -1,6 +1,7 @@ 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.GetAgentSettlementRatioHistoryItem import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioItem import kr.co.vividnext.sodalive.partner.agent.ratio.GetAgentSettlementRatioResponse import org.junit.jupiter.api.Assertions.assertEquals @@ -60,9 +61,18 @@ class AdminAgentSettlementRatioControllerTest { GetAgentSettlementRatioItem( memberId = 31L, nickname = "agent-a", - settlementRatio = 15, - effectiveFrom = LocalDateTime.of(2026, 4, 9, 10, 0), - effectiveTo = null + 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) + ) + ) ) ) ) @@ -73,9 +83,10 @@ class AdminAgentSettlementRatioControllerTest { assertEquals(true, response.success) assertEquals(1, response.data!!.totalCount) - assertEquals(15, response.data!!.items[0].settlementRatio) - assertEquals(LocalDateTime.of(2026, 4, 9, 10, 0), response.data!!.items[0].effectiveFrom) - assertEquals(null, response.data!!.items[0].effectiveTo) + assertEquals(15, response.data!!.items[0].current!!.settlementRatio) + assertEquals(LocalDateTime.of(2026, 4, 9, 10, 0), response.data!!.items[0].current!!.effectiveFrom) + assertEquals(null, response.data!!.items[0].current!!.effectiveTo) + assertEquals(1, response.data!!.items[0].history.size) Mockito.verify(service).getAgentSettlementRatio(offset = 20L, limit = 20L) } } diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AgentSettlementRatioServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AgentSettlementRatioServiceTest.kt index a3ce406f..edb69fff 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AgentSettlementRatioServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/admin/partner/agent/ratio/AgentSettlementRatioServiceTest.kt @@ -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.AgentSettlementRatioRepository 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.GetAgentSettlementRatioRow import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.BeforeEach @@ -345,24 +347,67 @@ class AgentSettlementRatioServiceTest { @DisplayName("관리자는 에이전트 정산 비율 목록을 조회할 수 있다") fun shouldGetAgentSettlementRatioList() { val items = listOf( - GetAgentSettlementRatioItem( + GetAgentSettlementRatioRow( memberId = 31L, nickname = "agent-a", settlementRatio = 15, effectiveFrom = LocalDateTime.of(2026, 4, 9, 10, 0), 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) val response = service.getAgentSettlementRatio(offset = 20L, limit = 20L) - assertEquals(1, response.totalCount) - assertEquals(1, response.items.size) - assertEquals(15, response.items[0].settlementRatio) - assertEquals(LocalDateTime.of(2026, 4, 9, 10, 0), response.items[0].effectiveFrom) - assertEquals(null, response.items[0].effectiveTo) + assertEquals(2, response.totalCount) + assertEquals(2, response.items.size) + assertEquals( + GetAgentSettlementRatioItem( + 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 + ) } }