From 51dae0f02c689ebc11d3b0cbcdda00c85a03a5b7 Mon Sep 17 00:00:00 2001 From: Klaus Date: Tue, 22 Apr 2025 15:39:45 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=82=AC?= =?UTF-8?q?=EC=9A=A9=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC=ED=98=84=20(?= =?UTF-8?q?=EB=A7=8C=EB=A3=8C=EC=9D=BC=20=EC=88=9C=20+=2010=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EB=8B=A8=EC=9C=84=20=EC=B0=A8=EA=B0=90)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/content/order/OrderService.kt | 11 ++++- .../sodalive/point/MemberPointRepository.kt | 26 ++++++++++- .../sodalive/point/PointUsageService.kt | 43 +++++++++++++++++++ .../sodalive/point/UsePointRepository.kt | 5 +++ 4 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/point/PointUsageService.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/point/UsePointRepository.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderService.kt index 630b22a..81e460f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderService.kt @@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.content.comment.AudioContentCommentRepository import kr.co.vividnext.sodalive.content.like.AudioContentLikeRepository import kr.co.vividnext.sodalive.content.main.GetAudioContentMainItem import kr.co.vividnext.sodalive.member.Member +import kr.co.vividnext.sodalive.point.PointUsageService import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -19,6 +20,7 @@ import java.time.LocalDateTime @Transactional(readOnly = true) class OrderService( private val repository: OrderRepository, + private val pointUsageService: PointUsageService, private val canPaymentService: CanPaymentService, private val audioContentRepository: AudioContentRepository, private val audioContentCommentQueryRepository: AudioContentCommentRepository, @@ -41,9 +43,16 @@ class OrderService( orderContent(orderType, content, member) } + val usedPoint = if (order.type == OrderType.RENTAL) { + pointUsageService.usePoint(member.id!!, order.can) + } else { + 0 + } + order.point = usedPoint + canPaymentService.spendCan( memberId = member.id!!, - needCan = order.can, + needCan = order.can - (usedPoint / 10), canUsage = CanUsage.ORDER_CONTENT, order = order, container = container diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/point/MemberPointRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/point/MemberPointRepository.kt index 1fec31b..d8aec5d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/point/MemberPointRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/point/MemberPointRepository.kt @@ -1,5 +1,29 @@ package kr.co.vividnext.sodalive.point +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.point.QMemberPoint.memberPoint import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDateTime -interface MemberPointRepository : JpaRepository +interface MemberPointRepository : JpaRepository, MemberPointQueryRepository + +interface MemberPointQueryRepository { + fun findByMemberIdAndExpiresAtAfterOrderByExpiresAtAsc(memberId: Long, expiresAt: LocalDateTime): List +} + +class MemberPointQueryRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : MemberPointQueryRepository { + override fun findByMemberIdAndExpiresAtAfterOrderByExpiresAtAsc( + memberId: Long, + expiresAt: LocalDateTime + ): List { + return queryFactory + .selectFrom(memberPoint) + .where( + memberPoint.memberId.eq(memberId), + memberPoint.expiresAt.goe(expiresAt) + ) + .fetch() + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/point/PointUsageService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/point/PointUsageService.kt new file mode 100644 index 0000000..ed02ca1 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/point/PointUsageService.kt @@ -0,0 +1,43 @@ +package kr.co.vividnext.sodalive.point + +import org.springframework.stereotype.Service +import java.time.LocalDateTime + +@Service +class PointUsageService( + private val memberPointRepository: MemberPointRepository, + private val usePointRepository: UsePointRepository +) { + fun usePoint(memberId: Long, contentPrice: Int): Int { + val now = LocalDateTime.now() + val maxUsablePoint = contentPrice * 10 + + val points = memberPointRepository.findByMemberIdAndExpiresAtAfterOrderByExpiresAtAsc( + memberId = memberId, + expiresAt = now + ) + + val totalAvailable = points.sumOf { it.point } + val usablePoint = minOf(totalAvailable, maxUsablePoint).floorToNearest10() + + var remaining = usablePoint + var used = 0 + + for (p in points) { + if (remaining <= 0) break + val usable = minOf(p.point, remaining) + p.point -= usable + remaining -= usable + used += usable + } + + if (used > 0) { + memberPointRepository.saveAll(points) + usePointRepository.save(UsePoint(memberId = memberId, amount = used)) + } + + return used + } + + private fun Int.floorToNearest10(): Int = (this / 10) * 10 +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/point/UsePointRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/point/UsePointRepository.kt new file mode 100644 index 0000000..49a5fcc --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/point/UsePointRepository.kt @@ -0,0 +1,5 @@ +package kr.co.vividnext.sodalive.point + +import org.springframework.data.jpa.repository.JpaRepository + +interface UsePointRepository : JpaRepository