diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/point/CreatePointRewardPolicyRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/point/CreatePointRewardPolicyRequest.kt index 4c2cf73..0f80f8a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/point/CreatePointRewardPolicyRequest.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/point/CreatePointRewardPolicyRequest.kt @@ -2,14 +2,17 @@ package kr.co.vividnext.sodalive.admin.point import kr.co.vividnext.sodalive.point.PointRewardPolicy import kr.co.vividnext.sodalive.useraction.ActionType +import kr.co.vividnext.sodalive.useraction.PolicyType import java.time.LocalDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter data class CreatePointRewardPolicyRequest( val title: String, + val policyType: PolicyType, val actionType: ActionType, val threshold: Int, + val availableCount: Int, val pointAmount: Int, val startDate: String, val endDate: String @@ -19,8 +22,10 @@ data class CreatePointRewardPolicyRequest( return PointRewardPolicy( title = title, + policyType = policyType, actionType = actionType, threshold = threshold, + availableCount = availableCount, pointAmount = pointAmount, startDate = LocalDateTime.parse(startDate, dateTimeFormatter) .atZone(ZoneId.of("Asia/Seoul")) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/point/PointGrantLog.kt b/src/main/kotlin/kr/co/vividnext/sodalive/point/PointGrantLog.kt index 780eccc..83666c6 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/point/PointGrantLog.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/point/PointGrantLog.kt @@ -12,5 +12,6 @@ data class PointGrantLog( val point: Int, @Enumerated(EnumType.STRING) val actionType: ActionType, - val policyId: Long? + val policyId: Long?, + val orderId: Long? ) : BaseEntity() diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/point/PointGrantLogRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/point/PointGrantLogRepository.kt index 361a873..8862ab6 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/point/PointGrantLogRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/point/PointGrantLogRepository.kt @@ -3,25 +3,27 @@ package kr.co.vividnext.sodalive.point import com.querydsl.jpa.impl.JPAQueryFactory import kr.co.vividnext.sodalive.point.QPointGrantLog.pointGrantLog import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDateTime interface PointGrantLogRepository : JpaRepository, PointGrantLogQueryRepository interface PointGrantLogQueryRepository { - fun existsByMemberIdAndPolicyId(memberId: Long, policyId: Long): Boolean + fun countByMemberIdAndPolicyIdAndStartDate(memberId: Long, policyId: Long, startDate: LocalDateTime): Int } class PointGrantLogQueryRepositoryImpl( private val queryFactory: JPAQueryFactory ) : PointGrantLogQueryRepository { - override fun existsByMemberIdAndPolicyId(memberId: Long, policyId: Long): Boolean { + override fun countByMemberIdAndPolicyIdAndStartDate(memberId: Long, policyId: Long, startDate: LocalDateTime): Int { return queryFactory .select(pointGrantLog.id) .from(pointGrantLog) .where( pointGrantLog.memberId.eq(memberId), - pointGrantLog.policyId.eq(policyId) + pointGrantLog.policyId.eq(policyId), + pointGrantLog.createdAt.goe(startDate) ) .fetch() - .isNotEmpty() + .size } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/point/PointRewardPolicy.kt b/src/main/kotlin/kr/co/vividnext/sodalive/point/PointRewardPolicy.kt index a898e1c..2fd9bd9 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/point/PointRewardPolicy.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/point/PointRewardPolicy.kt @@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.point import kr.co.vividnext.sodalive.common.BaseEntity import kr.co.vividnext.sodalive.useraction.ActionType +import kr.co.vividnext.sodalive.useraction.PolicyType import java.time.LocalDateTime import javax.persistence.Entity import javax.persistence.EnumType @@ -11,8 +12,11 @@ import javax.persistence.Enumerated data class PointRewardPolicy( var title: String, @Enumerated(EnumType.STRING) + val policyType: PolicyType, + @Enumerated(EnumType.STRING) val actionType: ActionType, val threshold: Int, + val availableCount: Int, val pointAmount: Int, var startDate: LocalDateTime, var endDate: LocalDateTime? = null, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/ActionType.kt b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/ActionType.kt index a9365c4..5933be9 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/ActionType.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/ActionType.kt @@ -2,5 +2,8 @@ package kr.co.vividnext.sodalive.useraction enum class ActionType(val displayName: String) { SIGN_UP("회원가입"), - USER_AUTHENTICATION("본인인증") + USER_AUTHENTICATION("본인인증"), + CONTENT_COMMENT("콘텐츠 댓글"), + ORDER_CONTENT_COMMENT("구매한 콘텐츠 댓글"), + LIVE_CONTINUOUS_LISTEN_30("라이브 연속 청취 30분") } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/PolicyType.kt b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/PolicyType.kt new file mode 100644 index 0000000..81f4982 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/PolicyType.kt @@ -0,0 +1,6 @@ +package kr.co.vividnext.sodalive.useraction + +enum class PolicyType(val displayName: String) { + DAILY("기간 내 매일"), + TOTAL("기간 내 전체") +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt index b3f0236..3f1a33d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/useraction/UserActionService.kt @@ -24,23 +24,35 @@ class UserActionService( private val coroutineScope = CoroutineScope(Dispatchers.IO) - fun recordAction(memberId: Long, actionType: ActionType, pushToken: String?) { + fun recordAction(memberId: Long, actionType: ActionType, orderId: Long? = null, pushToken: String? = null) { coroutineScope.launch { val now = LocalDateTime.now() repository.save(UserActionLog(memberId, actionType)) val policy = policyRepository.findByActionTypeAndIsActiveTrue(actionType, now) if (policy != null) { + val policyType = policy.policyType + val todayAt15 = now.toLocalDate().atTime(15, 0) + val policyTypeDailyStartDate = if (now.toLocalTime().isBefore(todayAt15.toLocalTime())) { + now.toLocalDate().minusDays(1).atTime(15, 0) + } else { + todayAt15 + } + val actionCount = repository.countByMemberIdAndActionTypeAndCreatedAtBetween( memberId = memberId, actionType = actionType, - startDate = policy.startDate, + startDate = if (policyType == PolicyType.DAILY) policyTypeDailyStartDate else policy.startDate, endDate = policy.endDate ?: now ) if (actionCount < policy.threshold) return@launch - val alreadyGranted = grantLogRepository.existsByMemberIdAndPolicyId(memberId, policy.id!!) - if (alreadyGranted) return@launch + val grantedCount = grantLogRepository.countByMemberIdAndPolicyIdAndStartDate( + memberId, + policy.id!!, + startDate = if (policyType == PolicyType.DAILY) policyTypeDailyStartDate else policy.startDate + ) + if (grantedCount >= policy.availableCount) return@launch memberPointRepository.save( MemberPoint( @@ -56,7 +68,8 @@ class UserActionService( memberId = memberId, point = policy.pointAmount, actionType = actionType, - policyId = policy.id!! + policyId = policy.id!!, + orderId = orderId ) )