Merge pull request 'fix(agent-calculate): 에이전트 기본 정산 비율을 7퍼센트로 조정한다' (#417) from test into main
Reviewed-on: #417
This commit is contained in:
18
docs/20260415_에이전트정산기본비율7퍼센트변경.md
Normal file
18
docs/20260415_에이전트정산기본비율7퍼센트변경.md
Normal 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` 검색 → 미검출.
|
||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user