fix: 유저 행동 데이터 기록시 포인트 지급 조건 수정
- 지급유형(매일, 전체) 추가 - 참여가능 횟수 추가 - 주문한 콘텐츠에 댓글을 쓰면 포인트 지급을 위해 포인트 지급 이력에 orderId 추가
This commit is contained in:
parent
73c9a90ae3
commit
f23251f5bb
|
@ -2,14 +2,17 @@ package kr.co.vividnext.sodalive.admin.point
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.point.PointRewardPolicy
|
import kr.co.vividnext.sodalive.point.PointRewardPolicy
|
||||||
import kr.co.vividnext.sodalive.useraction.ActionType
|
import kr.co.vividnext.sodalive.useraction.ActionType
|
||||||
|
import kr.co.vividnext.sodalive.useraction.PolicyType
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
data class CreatePointRewardPolicyRequest(
|
data class CreatePointRewardPolicyRequest(
|
||||||
val title: String,
|
val title: String,
|
||||||
|
val policyType: PolicyType,
|
||||||
val actionType: ActionType,
|
val actionType: ActionType,
|
||||||
val threshold: Int,
|
val threshold: Int,
|
||||||
|
val availableCount: Int,
|
||||||
val pointAmount: Int,
|
val pointAmount: Int,
|
||||||
val startDate: String,
|
val startDate: String,
|
||||||
val endDate: String
|
val endDate: String
|
||||||
|
@ -19,8 +22,10 @@ data class CreatePointRewardPolicyRequest(
|
||||||
|
|
||||||
return PointRewardPolicy(
|
return PointRewardPolicy(
|
||||||
title = title,
|
title = title,
|
||||||
|
policyType = policyType,
|
||||||
actionType = actionType,
|
actionType = actionType,
|
||||||
threshold = threshold,
|
threshold = threshold,
|
||||||
|
availableCount = availableCount,
|
||||||
pointAmount = pointAmount,
|
pointAmount = pointAmount,
|
||||||
startDate = LocalDateTime.parse(startDate, dateTimeFormatter)
|
startDate = LocalDateTime.parse(startDate, dateTimeFormatter)
|
||||||
.atZone(ZoneId.of("Asia/Seoul"))
|
.atZone(ZoneId.of("Asia/Seoul"))
|
||||||
|
|
|
@ -12,5 +12,6 @@ data class PointGrantLog(
|
||||||
val point: Int,
|
val point: Int,
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
val actionType: ActionType,
|
val actionType: ActionType,
|
||||||
val policyId: Long?
|
val policyId: Long?,
|
||||||
|
val orderId: Long?
|
||||||
) : BaseEntity()
|
) : BaseEntity()
|
||||||
|
|
|
@ -3,25 +3,27 @@ package kr.co.vividnext.sodalive.point
|
||||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||||
import kr.co.vividnext.sodalive.point.QPointGrantLog.pointGrantLog
|
import kr.co.vividnext.sodalive.point.QPointGrantLog.pointGrantLog
|
||||||
import org.springframework.data.jpa.repository.JpaRepository
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
interface PointGrantLogRepository : JpaRepository<PointGrantLog, Long>, PointGrantLogQueryRepository
|
interface PointGrantLogRepository : JpaRepository<PointGrantLog, Long>, PointGrantLogQueryRepository
|
||||||
|
|
||||||
interface PointGrantLogQueryRepository {
|
interface PointGrantLogQueryRepository {
|
||||||
fun existsByMemberIdAndPolicyId(memberId: Long, policyId: Long): Boolean
|
fun countByMemberIdAndPolicyIdAndStartDate(memberId: Long, policyId: Long, startDate: LocalDateTime): Int
|
||||||
}
|
}
|
||||||
|
|
||||||
class PointGrantLogQueryRepositoryImpl(
|
class PointGrantLogQueryRepositoryImpl(
|
||||||
private val queryFactory: JPAQueryFactory
|
private val queryFactory: JPAQueryFactory
|
||||||
) : PointGrantLogQueryRepository {
|
) : PointGrantLogQueryRepository {
|
||||||
override fun existsByMemberIdAndPolicyId(memberId: Long, policyId: Long): Boolean {
|
override fun countByMemberIdAndPolicyIdAndStartDate(memberId: Long, policyId: Long, startDate: LocalDateTime): Int {
|
||||||
return queryFactory
|
return queryFactory
|
||||||
.select(pointGrantLog.id)
|
.select(pointGrantLog.id)
|
||||||
.from(pointGrantLog)
|
.from(pointGrantLog)
|
||||||
.where(
|
.where(
|
||||||
pointGrantLog.memberId.eq(memberId),
|
pointGrantLog.memberId.eq(memberId),
|
||||||
pointGrantLog.policyId.eq(policyId)
|
pointGrantLog.policyId.eq(policyId),
|
||||||
|
pointGrantLog.createdAt.goe(startDate)
|
||||||
)
|
)
|
||||||
.fetch()
|
.fetch()
|
||||||
.isNotEmpty()
|
.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.point
|
||||||
|
|
||||||
import kr.co.vividnext.sodalive.common.BaseEntity
|
import kr.co.vividnext.sodalive.common.BaseEntity
|
||||||
import kr.co.vividnext.sodalive.useraction.ActionType
|
import kr.co.vividnext.sodalive.useraction.ActionType
|
||||||
|
import kr.co.vividnext.sodalive.useraction.PolicyType
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import javax.persistence.Entity
|
import javax.persistence.Entity
|
||||||
import javax.persistence.EnumType
|
import javax.persistence.EnumType
|
||||||
|
@ -11,8 +12,11 @@ import javax.persistence.Enumerated
|
||||||
data class PointRewardPolicy(
|
data class PointRewardPolicy(
|
||||||
var title: String,
|
var title: String,
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
|
val policyType: PolicyType,
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
val actionType: ActionType,
|
val actionType: ActionType,
|
||||||
val threshold: Int,
|
val threshold: Int,
|
||||||
|
val availableCount: Int,
|
||||||
val pointAmount: Int,
|
val pointAmount: Int,
|
||||||
var startDate: LocalDateTime,
|
var startDate: LocalDateTime,
|
||||||
var endDate: LocalDateTime? = null,
|
var endDate: LocalDateTime? = null,
|
||||||
|
|
|
@ -2,5 +2,8 @@ package kr.co.vividnext.sodalive.useraction
|
||||||
|
|
||||||
enum class ActionType(val displayName: String) {
|
enum class ActionType(val displayName: String) {
|
||||||
SIGN_UP("회원가입"),
|
SIGN_UP("회원가입"),
|
||||||
USER_AUTHENTICATION("본인인증")
|
USER_AUTHENTICATION("본인인증"),
|
||||||
|
CONTENT_COMMENT("콘텐츠 댓글"),
|
||||||
|
ORDER_CONTENT_COMMENT("구매한 콘텐츠 댓글"),
|
||||||
|
LIVE_CONTINUOUS_LISTEN_30("라이브 연속 청취 30분")
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package kr.co.vividnext.sodalive.useraction
|
||||||
|
|
||||||
|
enum class PolicyType(val displayName: String) {
|
||||||
|
DAILY("기간 내 매일"),
|
||||||
|
TOTAL("기간 내 전체")
|
||||||
|
}
|
|
@ -24,23 +24,35 @@ class UserActionService(
|
||||||
|
|
||||||
private val coroutineScope = CoroutineScope(Dispatchers.IO)
|
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 {
|
coroutineScope.launch {
|
||||||
val now = LocalDateTime.now()
|
val now = LocalDateTime.now()
|
||||||
repository.save(UserActionLog(memberId, actionType))
|
repository.save(UserActionLog(memberId, actionType))
|
||||||
|
|
||||||
val policy = policyRepository.findByActionTypeAndIsActiveTrue(actionType, now)
|
val policy = policyRepository.findByActionTypeAndIsActiveTrue(actionType, now)
|
||||||
if (policy != null) {
|
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(
|
val actionCount = repository.countByMemberIdAndActionTypeAndCreatedAtBetween(
|
||||||
memberId = memberId,
|
memberId = memberId,
|
||||||
actionType = actionType,
|
actionType = actionType,
|
||||||
startDate = policy.startDate,
|
startDate = if (policyType == PolicyType.DAILY) policyTypeDailyStartDate else policy.startDate,
|
||||||
endDate = policy.endDate ?: now
|
endDate = policy.endDate ?: now
|
||||||
)
|
)
|
||||||
if (actionCount < policy.threshold) return@launch
|
if (actionCount < policy.threshold) return@launch
|
||||||
|
|
||||||
val alreadyGranted = grantLogRepository.existsByMemberIdAndPolicyId(memberId, policy.id!!)
|
val grantedCount = grantLogRepository.countByMemberIdAndPolicyIdAndStartDate(
|
||||||
if (alreadyGranted) return@launch
|
memberId,
|
||||||
|
policy.id!!,
|
||||||
|
startDate = if (policyType == PolicyType.DAILY) policyTypeDailyStartDate else policy.startDate
|
||||||
|
)
|
||||||
|
if (grantedCount >= policy.availableCount) return@launch
|
||||||
|
|
||||||
memberPointRepository.save(
|
memberPointRepository.save(
|
||||||
MemberPoint(
|
MemberPoint(
|
||||||
|
@ -56,7 +68,8 @@ class UserActionService(
|
||||||
memberId = memberId,
|
memberId = memberId,
|
||||||
point = policy.pointAmount,
|
point = policy.pointAmount,
|
||||||
actionType = actionType,
|
actionType = actionType,
|
||||||
policyId = policy.id!!
|
policyId = policy.id!!,
|
||||||
|
orderId = orderId
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue