Merge pull request 'fix(agent-calculate): 에이전트 기본 정산 비율을 7퍼센트로 조정한다' (#417) from test into main

Reviewed-on: #417
This commit is contained in:
2026-04-15 05:37:24 +00:00
6 changed files with 86 additions and 20 deletions

View File

@@ -0,0 +1,18 @@
# 에이전트 정산 기본 비율 7퍼센트 변경 계획
- [x] `AgentCalculateQueryRepository`의 agent settlement fallback 10 적용 지점을 확인하고 7로 변경한다.
- [x] Kotlin 응답 계산 모델의 agent settlement fallback 10 상수를 7로 변경해 DB 집계와 계산 로직을 일치시킨다.
- [x] 기본 fallback 10을 전제한 관련 테스트 기대값을 7 기준으로 수정한다.
- [x] 관련 테스트와 진단을 실행하고 결과를 문서 하단 검증 기록에 누적한다.
## 검증 기록
- 1차 구현
- 무엇을: 에이전트 정산 비율 미설정 시 적용되는 기본 fallback 값을 `10%`에서 `7%`로 변경했다. `AgentCalculateQueryRepository`의 native SQL `COALESCE(asr.settlement_ratio, ...)`와 Kotlin 계산 모델 두 곳의 `DEFAULT_AGENT_SETTLEMENT_RATIO`를 함께 조정하고, 관련 테스트 기대값을 7% 기준으로 갱신했다.
- 왜: 현재 에이전트 정산 기본 비율 정책이 10%가 아니라 7%여야 하므로, DB 집계 결과와 Kotlin 응답 계산 결과가 동일한 기본값을 사용하도록 맞춰야 한다.
- 어떻게:
- `./gradlew test --tests kr.co.vividnext.sodalive.partner.agent.calculate.AgentCalculateServiceTest --tests kr.co.vividnext.sodalive.partner.agent.calculate.AgentCalculateQueryRepositoryTest` → 실패. 7% 기준으로 먼저 바꾼 테스트가 기존 10% fallback 구현 때문에 깨지는 것을 확인했다.
- `./gradlew test --tests kr.co.vividnext.sodalive.partner.agent.calculate.AgentCalculateServiceTest --tests kr.co.vividnext.sodalive.partner.agent.calculate.AgentCalculateQueryRepositoryTest --tests kr.co.vividnext.sodalive.admin.partner.agent.read.AdminAgentReadCurrentMonthListSummaryTest` → 성공.
- `./gradlew ktlintCheck` → 성공.
- `./gradlew build` → 성공.
- `src/main/kotlin`에서 `COALESCE(asr.settlement_ratio, 10)``DEFAULT_AGENT_SETTLEMENT_RATIO = 10` 검색 → 미검출.

View File

@@ -435,7 +435,7 @@ class AgentCalculateQueryRepository(
SELECT SELECT
COUNT(DISTINCT uc.id) AS count_value, COUNT(DISTINCT uc.id) AS count_value,
SUM(ucc.can) AS total_can, SUM(ucc.can) AS total_can,
COALESCE(asr.settlement_ratio, 10) AS agent_settlement_ratio COALESCE(asr.settlement_ratio, 7) AS agent_settlement_ratio
FROM use_can_calculate ucc FROM use_can_calculate ucc
INNER JOIN use_can uc ON ucc.use_can_id = uc.id INNER JOIN use_can uc ON ucc.use_can_id = uc.id
INNER JOIN member m ON m.id = ucc.recipient_creator_id INNER JOIN member m ON m.id = ucc.recipient_creator_id
@@ -451,7 +451,7 @@ class AgentCalculateQueryRepository(
AND ucc.status = 'RECEIVED' AND ucc.status = 'RECEIVED'
AND uc.created_at >= :startDate AND uc.created_at >= :startDate
AND uc.created_at <= :endDate AND uc.created_at <= :endDate
GROUP BY acr.id, asr.id, COALESCE(asr.settlement_ratio, 10) GROUP BY acr.id, asr.id, COALESCE(asr.settlement_ratio, 7)
) grouped ) grouped
""".trimIndent() """.trimIndent()
) )
@@ -812,7 +812,7 @@ class AgentCalculateQueryRepository(
COUNT(uc.id) AS count_value, COUNT(uc.id) AS count_value,
SUM(uc.can + uc.reward_can) AS total_can, SUM(uc.can + uc.reward_can) AS total_can,
COALESCE(csr.live_settlement_ratio, 70) AS settlement_ratio, COALESCE(csr.live_settlement_ratio, 70) AS settlement_ratio,
COALESCE(asr.settlement_ratio, 10) AS agent_settlement_ratio COALESCE(asr.settlement_ratio, 7) AS agent_settlement_ratio
FROM use_can uc FROM use_can uc
INNER JOIN live_room lr ON uc.room_id = lr.id INNER JOIN live_room lr ON uc.room_id = lr.id
INNER JOIN member m ON lr.member_id = m.id INNER JOIN member m ON lr.member_id = m.id
@@ -828,7 +828,7 @@ class AgentCalculateQueryRepository(
WHERE uc.is_refund = FALSE WHERE uc.is_refund = FALSE
AND uc.created_at >= :startDate AND uc.created_at >= :startDate
AND uc.created_at <= :endDate AND uc.created_at <= :endDate
GROUP BY acr.id, asr.id, COALESCE(csr.live_settlement_ratio, 70), COALESCE(asr.settlement_ratio, 10) GROUP BY acr.id, asr.id, COALESCE(csr.live_settlement_ratio, 70), COALESCE(asr.settlement_ratio, 7)
""".trimIndent() """.trimIndent()
private fun buildContentSettlementTotalSubQuery() = """ private fun buildContentSettlementTotalSubQuery() = """
@@ -836,7 +836,7 @@ class AgentCalculateQueryRepository(
COUNT(o.id) AS count_value, COUNT(o.id) AS count_value,
SUM(o.can) AS total_can, SUM(o.can) AS total_can,
COALESCE(COALESCE(c.settlement_ratio, csr.content_settlement_ratio), 70) AS settlement_ratio, COALESCE(COALESCE(c.settlement_ratio, csr.content_settlement_ratio), 70) AS settlement_ratio,
COALESCE(asr.settlement_ratio, 10) AS agent_settlement_ratio COALESCE(asr.settlement_ratio, 7) AS agent_settlement_ratio
FROM orders o FROM orders o
INNER JOIN content c ON o.content_id = c.id INNER JOIN content c ON o.content_id = c.id
INNER JOIN member m ON c.member_id = m.id INNER JOIN member m ON c.member_id = m.id
@@ -857,7 +857,7 @@ class AgentCalculateQueryRepository(
asr.id, asr.id,
COALESCE(c.settlement_ratio, csr.content_settlement_ratio), COALESCE(c.settlement_ratio, csr.content_settlement_ratio),
COALESCE(COALESCE(c.settlement_ratio, csr.content_settlement_ratio), 70), COALESCE(COALESCE(c.settlement_ratio, csr.content_settlement_ratio), 70),
COALESCE(asr.settlement_ratio, 10) COALESCE(asr.settlement_ratio, 7)
""".trimIndent() """.trimIndent()
private fun buildCommunitySettlementTotalSubQuery() = """ private fun buildCommunitySettlementTotalSubQuery() = """
@@ -865,7 +865,7 @@ class AgentCalculateQueryRepository(
COUNT(uc.id) AS count_value, COUNT(uc.id) AS count_value,
SUM(uc.can + uc.reward_can) AS total_can, SUM(uc.can + uc.reward_can) AS total_can,
COALESCE(csr.community_settlement_ratio, 70) AS settlement_ratio, COALESCE(csr.community_settlement_ratio, 70) AS settlement_ratio,
COALESCE(asr.settlement_ratio, 10) AS agent_settlement_ratio COALESCE(asr.settlement_ratio, 7) AS agent_settlement_ratio
FROM use_can uc FROM use_can uc
INNER JOIN creator_community cc ON uc.creator_community_id = cc.id INNER JOIN creator_community cc ON uc.creator_community_id = cc.id
INNER JOIN member m ON cc.member_id = m.id INNER JOIN member m ON cc.member_id = m.id
@@ -882,7 +882,7 @@ class AgentCalculateQueryRepository(
AND uc.can_usage = 'PAID_COMMUNITY_POST' AND uc.can_usage = 'PAID_COMMUNITY_POST'
AND uc.created_at >= :startDate AND uc.created_at >= :startDate
AND uc.created_at <= :endDate AND uc.created_at <= :endDate
GROUP BY acr.id, asr.id, COALESCE(csr.community_settlement_ratio, 70), COALESCE(asr.settlement_ratio, 10) GROUP BY acr.id, asr.id, COALESCE(csr.community_settlement_ratio, 70), COALESCE(asr.settlement_ratio, 7)
""".trimIndent() """.trimIndent()
private fun buildContentDonationSettlementTotalSubQuery() = """ private fun buildContentDonationSettlementTotalSubQuery() = """
@@ -890,7 +890,7 @@ class AgentCalculateQueryRepository(
COUNT(uc.id) AS count_value, COUNT(uc.id) AS count_value,
SUM(uc.can + uc.reward_can) AS total_can, SUM(uc.can + uc.reward_can) AS total_can,
70 AS settlement_ratio, 70 AS settlement_ratio,
COALESCE(asr.settlement_ratio, 10) AS agent_settlement_ratio COALESCE(asr.settlement_ratio, 7) AS agent_settlement_ratio
FROM use_can uc FROM use_can uc
INNER JOIN content c ON uc.content_id = c.id INNER JOIN content c ON uc.content_id = c.id
INNER JOIN member m ON c.member_id = m.id INNER JOIN member m ON c.member_id = m.id
@@ -905,7 +905,7 @@ class AgentCalculateQueryRepository(
AND uc.can_usage = 'DONATION' AND uc.can_usage = 'DONATION'
AND uc.created_at >= :startDate AND uc.created_at >= :startDate
AND uc.created_at <= :endDate AND uc.created_at <= :endDate
GROUP BY acr.id, asr.id, COALESCE(asr.settlement_ratio, 10) GROUP BY acr.id, asr.id, COALESCE(asr.settlement_ratio, 7)
""".trimIndent() """.trimIndent()
private fun Any?.toIntValue(): Int { private fun Any?.toIntValue(): Int {

View File

@@ -64,7 +64,7 @@ data class GetAgentChannelDonationSettlementByCreatorQueryData @QueryProjection
} }
companion object { companion object {
private const val DEFAULT_AGENT_SETTLEMENT_RATIO = 10 private const val DEFAULT_AGENT_SETTLEMENT_RATIO = 7
} }
} }

View File

@@ -46,7 +46,7 @@ data class GetAgentCreatorSettlementSummaryQueryData @QueryProjection constructo
private val TAX_RATE = BigDecimal("0.033") private val TAX_RATE = BigDecimal("0.033")
private val PERCENT_DIVISOR = BigDecimal("100") private val PERCENT_DIVISOR = BigDecimal("100")
private const val DEFAULT_SETTLEMENT_RATIO = 70 private const val DEFAULT_SETTLEMENT_RATIO = 70
private const val DEFAULT_AGENT_SETTLEMENT_RATIO = 10 private const val DEFAULT_AGENT_SETTLEMENT_RATIO = 7
private fun calculateAgentSettlementAmount(settlementAmount: Int, agentSettlementRatio: Int): Int { private fun calculateAgentSettlementAmount(settlementAmount: Int, agentSettlementRatio: Int): Int {
return BigDecimal(settlementAmount) return BigDecimal(settlementAmount)

View File

@@ -380,6 +380,54 @@ class AgentCalculateQueryRepositoryTest @Autowired constructor(
assertEquals(kotlinTotal, dbTotal) assertEquals(kotlinTotal, dbTotal)
} }
@Test
@DisplayName("에이전트 비율 이력이 없으면 콘텐츠 후원 응답은 7퍼센트 기본값으로 agent 정산금을 계산한다")
fun shouldApplySevenPercentDefaultAgentSettlementRatioToContentDonationWhenAgentRatioHistoryDoesNotExist() {
val agent = saveMember("agent-default-content-donation", MemberRole.AGENT)
val creator = saveMember("creator-default-content-donation", MemberRole.CREATOR)
val buyer = saveMember("buyer-default-content-donation", MemberRole.USER)
saveRelation(agent, creator)
val donationContent = saveAudioContent(creator, "content-default-agent-ratio", price = 0, settlementRatio = null)
saveContentDonationUseCan(buyer, donationContent, 20, LocalDateTime.of(2026, 2, 20, 10, 0, 0))
val response = service.getCalculateContentDonationByCreator("2026-02-20", "2026-02-20", agent.id!!, 0, 10)
assertGenericSettlementResponse(
response,
expectedCount = 1,
expectedTotalCan = 20,
expectedAgentSettlementAmount = calculateGenericAgentSettlementAmount(
totalCan = 20,
settlementRatio = 70,
agentSettlementRatio = 7
)
)
}
@Test
@DisplayName("에이전트 비율 이력이 없으면 채널후원 응답은 7퍼센트 기본값으로 agent 정산금을 계산한다")
fun shouldApplySevenPercentDefaultAgentSettlementRatioToChannelDonationWhenAgentRatioHistoryDoesNotExist() {
val agent = saveMember("agent-default-channel-donation", MemberRole.AGENT)
val creator = saveMember("creator-default-channel-donation", MemberRole.CREATOR)
val sender = saveMember("sender-default-channel-donation", MemberRole.USER)
saveRelation(agent, creator)
val channelDonation = saveChannelDonationUseCan(sender, 50, LocalDateTime.of(2026, 2, 20, 10, 0, 0))
saveUseCanCalculate(channelDonation, creator.id!!, 50, PaymentGateway.PG)
val response = service.getChannelDonationByCreator("2026-02-20", "2026-02-20", agent.id!!, 0, 10)
assertChannelDonationSettlementResponse(
response,
expectedCount = 1,
expectedTotalCan = 50,
expectedAgentSettlementAmount = calculateChannelAgentSettlementAmount(totalCan = 50, agentSettlementRatio = 7)
)
}
@Test @Test
@DisplayName("페이지 대상 creator가 없으면 모든 카테고리 조회는 빈 rows를 반환한다") @DisplayName("페이지 대상 creator가 없으면 모든 카테고리 조회는 빈 rows를 반환한다")
fun shouldReturnEmptyRowsWhenPagedCreatorSelectionIsEmptyAcrossAllCategories() { fun shouldReturnEmptyRowsWhenPagedCreatorSelectionIsEmptyAcrossAllCategories() {

View File

@@ -358,7 +358,7 @@ class AgentCalculateServiceTest {
} }
@Test @Test
@DisplayName("에이전트 비율 이력이 없으면 일반 정산 응답은 10퍼센트 기본값으로 agent 정산금을 계산한다") @DisplayName("에이전트 비율 이력이 없으면 일반 정산 응답은 7퍼센트 기본값으로 agent 정산금을 계산한다")
fun shouldApplyDefaultAgentSettlementRatioWhenAgentRatioHistoryDoesNotExist() { fun shouldApplyDefaultAgentSettlementRatioWhenAgentRatioHistoryDoesNotExist() {
val queryData = listOf( val queryData = listOf(
GetAgentCreatorSettlementSummaryQueryData( GetAgentCreatorSettlementSummaryQueryData(
@@ -393,7 +393,7 @@ class AgentCalculateServiceTest {
settlementAmount = 1_308, settlementAmount = 1_308,
tax = 43, tax = 43,
depositAmount = 1_265, depositAmount = 1_265,
agentSettlementAmount = 131 agentSettlementAmount = 92
) )
) )
Mockito.`when`( Mockito.`when`(
@@ -416,8 +416,8 @@ class AgentCalculateServiceTest {
assertEquals(1, response.totalCount) assertEquals(1, response.totalCount)
assertEquals(1_308, response.total.settlementAmount) assertEquals(1_308, response.total.settlementAmount)
assertEquals(131, response.total.agentSettlementAmount) assertEquals(92, response.total.agentSettlementAmount)
assertEquals(131, response.items[0].agentSettlementAmount) assertEquals(92, response.items[0].agentSettlementAmount)
} }
@Test @Test
@@ -493,7 +493,7 @@ class AgentCalculateServiceTest {
} }
@Test @Test
@DisplayName("에이전트 비율 이력이 없으면 채널후원 응답은 10퍼센트 기본값으로 agent 정산금을 계산한다") @DisplayName("에이전트 비율 이력이 없으면 채널후원 응답은 7퍼센트 기본값으로 agent 정산금을 계산한다")
fun shouldApplyDefaultAgentSettlementRatioToChannelDonationWhenAgentRatioHistoryDoesNotExist() { fun shouldApplyDefaultAgentSettlementRatioToChannelDonationWhenAgentRatioHistoryDoesNotExist() {
val queryData = listOf( val queryData = listOf(
GetAgentChannelDonationSettlementByCreatorQueryData( GetAgentChannelDonationSettlementByCreatorQueryData(
@@ -527,7 +527,7 @@ class AgentCalculateServiceTest {
settlementAmount = 3_970, settlementAmount = 3_970,
withholdingTax = 131, withholdingTax = 131,
depositAmount = 3_839, depositAmount = 3_839,
agentSettlementAmount = 397 agentSettlementAmount = 278
) )
) )
Mockito.`when`( Mockito.`when`(
@@ -550,8 +550,8 @@ class AgentCalculateServiceTest {
assertEquals(1, response.totalCount) assertEquals(1, response.totalCount)
assertEquals(3_970, response.total.settlementAmount) assertEquals(3_970, response.total.settlementAmount)
assertEquals(397, response.total.agentSettlementAmount) assertEquals(278, response.total.agentSettlementAmount)
assertEquals(397, response.items[0].agentSettlementAmount) assertEquals(278, response.items[0].agentSettlementAmount)
} }
@Test @Test