feat(calculate-ratio): 정산 비율 수정/삭제(소프트 삭제)와 업서트, 쿼리 보강

- deletedAt 기반 소프트 삭제 도입 및 restore/updateValues 추가
- 생성 시 기존(삭제 포함) 레코드 복구 후 값 갱신(업서트)
- /admin/calculate/ratio/update, /delete 엔드포인트 추가
- 정산 쿼리 조인에 deletedAt.isNull 적용하여 삭제 데이터 배제
- 목록/카운트 조회에서도 삭제 데이터 제외
This commit is contained in:
2025-09-22 13:36:36 +09:00
parent a6dfa81ba6
commit 97e95b51ab
6 changed files with 135 additions and 21 deletions

View File

@@ -39,7 +39,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(useCan.room, liveRoom) .innerJoin(useCan.room, liveRoom)
.innerJoin(liveRoom.member, member) .innerJoin(liveRoom.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
useCan.isRefund.isFalse useCan.isRefund.isFalse
.and(useCan.createdAt.goe(startDate)) .and(useCan.createdAt.goe(startDate))
@@ -75,7 +78,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(order.audioContent, audioContent) .innerJoin(order.audioContent, audioContent)
.innerJoin(audioContent.member, member) .innerJoin(audioContent.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
order.createdAt.goe(startDate) order.createdAt.goe(startDate)
.and(order.createdAt.loe(endDate)) .and(order.createdAt.loe(endDate))
@@ -142,7 +148,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(order.audioContent, audioContent) .innerJoin(order.audioContent, audioContent)
.innerJoin(audioContent.member, member) .innerJoin(audioContent.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where(order.isActive.isTrue) .where(order.isActive.isTrue)
.groupBy( .groupBy(
member.id, member.id,
@@ -230,7 +239,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(useCan.communityPost, creatorCommunity) .innerJoin(useCan.communityPost, creatorCommunity)
.innerJoin(creatorCommunity.member, member) .innerJoin(creatorCommunity.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
useCan.isRefund.isFalse useCan.isRefund.isFalse
.and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST)) .and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST))
@@ -251,7 +263,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(useCan.room, liveRoom) .innerJoin(useCan.room, liveRoom)
.innerJoin(liveRoom.member, member) .innerJoin(liveRoom.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
useCan.isRefund.isFalse useCan.isRefund.isFalse
.and(useCan.createdAt.goe(startDate)) .and(useCan.createdAt.goe(startDate))
@@ -281,7 +296,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(useCan.room, liveRoom) .innerJoin(useCan.room, liveRoom)
.innerJoin(liveRoom.member, member) .innerJoin(liveRoom.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
useCan.isRefund.isFalse useCan.isRefund.isFalse
.and(useCan.createdAt.goe(startDate)) .and(useCan.createdAt.goe(startDate))
@@ -301,7 +319,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(order.audioContent, audioContent) .innerJoin(order.audioContent, audioContent)
.innerJoin(audioContent.member, member) .innerJoin(audioContent.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
order.createdAt.goe(startDate) order.createdAt.goe(startDate)
.and(order.createdAt.loe(endDate)) .and(order.createdAt.loe(endDate))
@@ -331,7 +352,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(order.audioContent, audioContent) .innerJoin(order.audioContent, audioContent)
.innerJoin(audioContent.member, member) .innerJoin(audioContent.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
order.createdAt.goe(startDate) order.createdAt.goe(startDate)
.and(order.createdAt.loe(endDate)) .and(order.createdAt.loe(endDate))
@@ -351,7 +375,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(useCan.communityPost, creatorCommunity) .innerJoin(useCan.communityPost, creatorCommunity)
.innerJoin(creatorCommunity.member, member) .innerJoin(creatorCommunity.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
useCan.isRefund.isFalse useCan.isRefund.isFalse
.and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST)) .and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST))
@@ -382,7 +409,10 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) {
.innerJoin(useCan.communityPost, creatorCommunity) .innerJoin(useCan.communityPost, creatorCommunity)
.innerJoin(creatorCommunity.member, member) .innerJoin(creatorCommunity.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
useCan.isRefund.isFalse useCan.isRefund.isFalse
.and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST)) .and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST))

View File

@@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.admin.calculate.ratio
import kr.co.vividnext.sodalive.common.BaseEntity import kr.co.vividnext.sodalive.common.BaseEntity
import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.Member
import java.time.LocalDateTime
import javax.persistence.Entity import javax.persistence.Entity
import javax.persistence.FetchType import javax.persistence.FetchType
import javax.persistence.JoinColumn import javax.persistence.JoinColumn
@@ -9,12 +10,29 @@ import javax.persistence.OneToOne
@Entity @Entity
data class CreatorSettlementRatio( data class CreatorSettlementRatio(
val subsidy: Int, var subsidy: Int,
val liveSettlementRatio: Int, var liveSettlementRatio: Int,
val contentSettlementRatio: Int, var contentSettlementRatio: Int,
val communitySettlementRatio: Int var communitySettlementRatio: Int
) : BaseEntity() { ) : BaseEntity() {
@OneToOne(fetch = FetchType.LAZY) @OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", nullable = false) @JoinColumn(name = "member_id", nullable = false)
var member: Member? = null var member: Member? = null
var deletedAt: LocalDateTime? = null
fun softDelete() {
this.deletedAt = LocalDateTime.now()
}
fun restore() {
this.deletedAt = null
}
fun updateValues(subsidy: Int, live: Int, content: Int, community: Int) {
this.subsidy = subsidy
this.liveSettlementRatio = live
this.contentSettlementRatio = content
this.communitySettlementRatio = community
}
} }

View File

@@ -27,4 +27,14 @@ class CreatorSettlementRatioController(private val service: CreatorSettlementRat
limit = pageable.pageSize.toLong() limit = pageable.pageSize.toLong()
) )
) )
@PostMapping("/update")
fun updateCreatorSettlementRatio(
@RequestBody request: CreateCreatorSettlementRatioRequest
) = ApiResponse.ok(service.updateCreatorSettlementRatio(request))
@PostMapping("/delete")
fun deleteCreatorSettlementRatio(
@RequestBody memberId: Long
) = ApiResponse.ok(service.deleteCreatorSettlementRatio(memberId))
} }

View File

@@ -7,7 +7,9 @@ import org.springframework.data.jpa.repository.JpaRepository
interface CreatorSettlementRatioRepository : interface CreatorSettlementRatioRepository :
JpaRepository<CreatorSettlementRatio, Long>, JpaRepository<CreatorSettlementRatio, Long>,
CreatorSettlementRatioQueryRepository CreatorSettlementRatioQueryRepository {
fun findByMemberId(memberId: Long): CreatorSettlementRatio?
}
interface CreatorSettlementRatioQueryRepository { interface CreatorSettlementRatioQueryRepository {
fun getCreatorSettlementRatio(offset: Long, limit: Long): List<GetCreatorSettlementRatioItem> fun getCreatorSettlementRatio(offset: Long, limit: Long): List<GetCreatorSettlementRatioItem>
@@ -30,6 +32,7 @@ class CreatorSettlementRatioQueryRepositoryImpl(
) )
.from(creatorSettlementRatio) .from(creatorSettlementRatio)
.innerJoin(creatorSettlementRatio.member, member) .innerJoin(creatorSettlementRatio.member, member)
.where(creatorSettlementRatio.deletedAt.isNull)
.orderBy(creatorSettlementRatio.id.asc()) .orderBy(creatorSettlementRatio.id.asc())
.offset(offset) .offset(offset)
.limit(limit) .limit(limit)
@@ -40,6 +43,7 @@ class CreatorSettlementRatioQueryRepositoryImpl(
return queryFactory return queryFactory
.select(creatorSettlementRatio.id) .select(creatorSettlementRatio.id)
.from(creatorSettlementRatio) .from(creatorSettlementRatio)
.where(creatorSettlementRatio.deletedAt.isNull)
.fetch() .fetch()
.size .size
} }

View File

@@ -14,8 +14,6 @@ class CreatorSettlementRatioService(
) { ) {
@Transactional @Transactional
fun createCreatorSettlementRatio(request: CreateCreatorSettlementRatioRequest) { fun createCreatorSettlementRatio(request: CreateCreatorSettlementRatioRequest) {
val creatorSettlementRatio = request.toEntity()
val creator = memberRepository.findByIdOrNull(request.memberId) val creator = memberRepository.findByIdOrNull(request.memberId)
?: throw SodaException("잘못된 크리에이터 입니다.") ?: throw SodaException("잘못된 크리에이터 입니다.")
@@ -23,10 +21,52 @@ class CreatorSettlementRatioService(
throw SodaException("잘못된 크리에이터 입니다.") throw SodaException("잘못된 크리에이터 입니다.")
} }
val existing = repository.findByMemberId(request.memberId)
if (existing != null) {
// revive if soft-deleted, then update values
existing.restore()
existing.updateValues(
request.subsidy,
request.liveSettlementRatio,
request.contentSettlementRatio,
request.communitySettlementRatio
)
repository.save(existing)
return
}
val creatorSettlementRatio = request.toEntity()
creatorSettlementRatio.member = creator creatorSettlementRatio.member = creator
repository.save(creatorSettlementRatio) repository.save(creatorSettlementRatio)
} }
@Transactional
fun updateCreatorSettlementRatio(request: CreateCreatorSettlementRatioRequest) {
val creator = memberRepository.findByIdOrNull(request.memberId)
?: throw SodaException("잘못된 크리에이터 입니다.")
if (creator.role != MemberRole.CREATOR) {
throw SodaException("잘못된 크리에이터 입니다.")
}
val existing = repository.findByMemberId(request.memberId)
?: throw SodaException("해당 크리에이터의 정산 비율 설정이 없습니다.")
existing.restore()
existing.updateValues(
request.subsidy,
request.liveSettlementRatio,
request.contentSettlementRatio,
request.communitySettlementRatio
)
repository.save(existing)
}
@Transactional
fun deleteCreatorSettlementRatio(memberId: Long) {
val existing = repository.findByMemberId(memberId)
?: throw SodaException("해당 크리에이터의 정산 비율 설정이 없습니다.")
existing.softDelete()
repository.save(existing)
}
@Transactional(readOnly = true) @Transactional(readOnly = true)
fun getCreatorSettlementRatio(offset: Long, limit: Long): GetCreatorSettlementRatioResponse { fun getCreatorSettlementRatio(offset: Long, limit: Long): GetCreatorSettlementRatioResponse {
val totalCount = repository.getCreatorSettlementRatioTotalCount() val totalCount = repository.getCreatorSettlementRatioTotalCount()

View File

@@ -53,7 +53,10 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac
.innerJoin(useCan.room, liveRoom) .innerJoin(useCan.room, liveRoom)
.innerJoin(liveRoom.member, member) .innerJoin(liveRoom.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
useCan.isRefund.isFalse useCan.isRefund.isFalse
.and(useCan.createdAt.goe(startDate)) .and(useCan.createdAt.goe(startDate))
@@ -119,7 +122,10 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac
.innerJoin(order.audioContent, audioContent) .innerJoin(order.audioContent, audioContent)
.innerJoin(audioContent.member, member) .innerJoin(audioContent.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
order.createdAt.goe(startDate) order.createdAt.goe(startDate)
.and(order.createdAt.loe(endDate)) .and(order.createdAt.loe(endDate))
@@ -196,7 +202,10 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac
.innerJoin(order.audioContent, audioContent) .innerJoin(order.audioContent, audioContent)
.innerJoin(audioContent.member, member) .innerJoin(audioContent.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
audioContent.member.id.eq(memberId) audioContent.member.id.eq(memberId)
.and(order.isActive.isTrue) .and(order.isActive.isTrue)
@@ -318,7 +327,10 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac
.innerJoin(useCan.communityPost, creatorCommunity) .innerJoin(useCan.communityPost, creatorCommunity)
.innerJoin(creatorCommunity.member, member) .innerJoin(creatorCommunity.member, member)
.leftJoin(creatorSettlementRatio) .leftJoin(creatorSettlementRatio)
.on(member.id.eq(creatorSettlementRatio.member.id)) .on(
member.id.eq(creatorSettlementRatio.member.id)
.and(creatorSettlementRatio.deletedAt.isNull)
)
.where( .where(
useCan.isRefund.isFalse useCan.isRefund.isFalse
.and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST)) .and(useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST))