test #316

Merged
klaus merged 20 commits from test into main 2025-05-20 06:03:11 +00:00
7 changed files with 45 additions and 11 deletions
Showing only changes of commit f23251f5bb - Show all commits

View File

@ -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"))

View File

@ -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()

View File

@ -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<PointGrantLog, Long>, 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
}
}

View File

@ -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,

View File

@ -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분")
}

View File

@ -0,0 +1,6 @@
package kr.co.vividnext.sodalive.useraction
enum class PolicyType(val displayName: String) {
DAILY("기간 내 매일"),
TOTAL("기간 내 전체")
}

View File

@ -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
)
)