抽奖活动奖励配置和领取功能完善
This commit is contained in:
parent
d279c549c1
commit
bb8b1c5c1f
@ -1,11 +1,14 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.ActivityRewardConfigCO;
|
||||
import com.red.circle.other.app.dto.cmd.activity.ActivityRewardConfigCmd;
|
||||
import com.red.circle.other.domain.gateway.props.ActivitySourceGroupGateway;
|
||||
import com.red.circle.other.infra.database.rds.dao.activity.UserActivityRewardClaimDAO;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.UserActivityRewardClaim;
|
||||
import com.red.circle.other.inner.enums.activity.PropsActivityTypeEnum;
|
||||
import com.red.circle.other.inner.model.dto.activity.props.ActivityPropsGroup;
|
||||
import com.red.circle.other.inner.model.dto.activity.props.ActivityPropsRule;
|
||||
@ -14,6 +17,7 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@ -25,6 +29,7 @@ import java.util.stream.Collectors;
|
||||
public class ActivityRewardConfigQryExe {
|
||||
|
||||
private final ActivitySourceGroupGateway activitySourceGroupGateway;
|
||||
private final UserActivityRewardClaimDAO userActivityRewardClaimDAO;
|
||||
|
||||
public List<ActivityRewardConfigCO> execute(ActivityRewardConfigCmd cmd) {
|
||||
PropsActivityTypeEnum activityType = PropsActivityTypeEnum.valueOf(cmd.getActivityType());
|
||||
@ -35,13 +40,28 @@ public class ActivityRewardConfigQryExe {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
List<Long> ruleIds = ruleConfigs.stream().map(ActivityPropsRule::getId).collect(Collectors.toList());
|
||||
Map<Long, UserActivityRewardClaim> claimMap = getUserClaimMap(cmd.getReqUserId(), ruleIds);
|
||||
|
||||
return ruleConfigs.stream()
|
||||
.map(rule -> buildRewardConfig(rule, cmd.getReqSysOrigin().getOrigin()))
|
||||
.map(rule -> buildRewardConfig(rule, cmd.getReqSysOrigin().getOrigin(), claimMap))
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private ActivityRewardConfigCO buildRewardConfig(ActivityPropsRule rule, String sysOrigin) {
|
||||
private Map<Long, UserActivityRewardClaim> getUserClaimMap(Long userId, List<Long> ruleIds) {
|
||||
List<UserActivityRewardClaim> claims = userActivityRewardClaimDAO.selectList(
|
||||
new LambdaQueryWrapper<UserActivityRewardClaim>()
|
||||
.eq(UserActivityRewardClaim::getUserId, userId)
|
||||
.in(UserActivityRewardClaim::getRuleId, ruleIds)
|
||||
);
|
||||
|
||||
return claims.stream()
|
||||
.collect(Collectors.toMap(UserActivityRewardClaim::getRuleId, claim -> claim, (a, b) -> a));
|
||||
}
|
||||
|
||||
private ActivityRewardConfigCO buildRewardConfig(ActivityPropsRule rule, String sysOrigin,
|
||||
Map<Long, UserActivityRewardClaim> claimMap) {
|
||||
ActivityPropsGroup group = activitySourceGroupGateway.getActivityPropsGroup(
|
||||
sysOrigin,
|
||||
rule.getResourceGroupId()
|
||||
@ -62,6 +82,9 @@ public class ActivityRewardConfigQryExe {
|
||||
.setGroupName(group.getName())
|
||||
.setShelfStatus(group.getShelfStatus());
|
||||
|
||||
UserActivityRewardClaim claim = claimMap.get(rule.getId());
|
||||
config.setClaimStatus(Objects.isNull(claim) ? 0 : claim.getStatus());
|
||||
|
||||
if (CollectionUtil.isNotEmpty(group.getActivityRewardProps())) {
|
||||
List<ActivityRewardConfigCO.ActivityRewardPropsCO> propsList = group.getActivityRewardProps().stream()
|
||||
.map(this::convertToRewardPropsCO)
|
||||
|
||||
@ -1,18 +1,22 @@
|
||||
package com.red.circle.other.app.command.activity;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||
import com.red.circle.other.app.dto.clientobject.activity.ClaimRewardResultCO;
|
||||
import com.red.circle.other.app.dto.cmd.activity.ClaimActivityRewardCmd;
|
||||
import com.red.circle.other.domain.gateway.props.ActivitySourceGroupGateway;
|
||||
import com.red.circle.other.infra.database.rds.dao.activity.UserActivityRewardClaimDAO;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.UserActivityRewardClaim;
|
||||
import com.red.circle.other.infra.database.rds.service.activity.UserActivityRechargeService;
|
||||
import com.red.circle.other.inner.asserts.OtherErrorCode;
|
||||
import com.red.circle.other.inner.asserts.user.UserErrorCode;
|
||||
import com.red.circle.other.inner.endpoint.activity.LotteryTicketClient;
|
||||
import com.red.circle.other.inner.enums.activity.PropsActivityTypeEnum;
|
||||
import com.red.circle.other.inner.model.dto.activity.props.ActivityPropsRule;
|
||||
import com.red.circle.other.inner.asserts.DynamicErrorCode;
|
||||
import com.red.circle.tool.core.date.TimestampUtils;
|
||||
import com.red.circle.tool.core.json.JacksonUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@ -20,6 +24,7 @@ import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@ -34,6 +39,8 @@ public class ClaimActivityRewardExe {
|
||||
|
||||
private final ActivitySourceGroupGateway activitySourceGroupGateway;
|
||||
private final UserActivityRechargeService userActivityRechargeService;
|
||||
private final UserActivityRewardClaimDAO userActivityRewardClaimDAO;
|
||||
private final LotteryTicketClient lotteryTicketClient;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ClaimRewardResultCO execute(ClaimActivityRewardCmd cmd) {
|
||||
@ -43,12 +50,21 @@ public class ClaimActivityRewardExe {
|
||||
List<ActivityPropsRule> ruleConfigs = activitySourceGroupGateway.listRule(sysOrigin, activityType);
|
||||
ActivityPropsRule targetRule = ruleConfigs.stream()
|
||||
.filter(rule -> Objects.equals(rule.getId(), cmd.getRuleId()))
|
||||
.findFirst().orElse(null);
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
|
||||
ResponseAssert.isTrue(CommonErrorCode.DATA_ERROR, targetRule != null);
|
||||
ResponseAssert.notNull(DynamicErrorCode.NO_RELATED_INFORMATION_FOUND, targetRule);
|
||||
|
||||
long count = userActivityRewardClaimDAO.selectCount(
|
||||
new LambdaQueryWrapper<UserActivityRewardClaim>()
|
||||
.eq(UserActivityRewardClaim::getUserId, cmd.getReqUserId())
|
||||
.eq(UserActivityRewardClaim::getRuleId, cmd.getRuleId())
|
||||
);
|
||||
|
||||
ResponseAssert.isFalse(CommonErrorCode.REPEATED_SUBMISSION, count > 0);
|
||||
|
||||
BigDecimal requiredAmount = parseRequiredAmount(targetRule.getJsonData());
|
||||
ResponseAssert.isTrue(CommonErrorCode.DATA_ERROR, requiredAmount != null);
|
||||
ResponseAssert.notNull(DynamicErrorCode.NO_RELATED_INFORMATION_FOUND, requiredAmount);
|
||||
|
||||
BigDecimal userTotalAmount = userActivityRechargeService.getUserTotalAmount(
|
||||
cmd.getActivityId(),
|
||||
@ -57,15 +73,39 @@ public class ClaimActivityRewardExe {
|
||||
|
||||
ResponseAssert.isFalse(OtherErrorCode.USER_RECHARGE_INVALID, Objects.isNull(userTotalAmount) || userTotalAmount.compareTo(requiredAmount) < 0);
|
||||
|
||||
Integer ticketCount = parseTicketCount(targetRule.getJsonData());
|
||||
if (Objects.isNull(ticketCount) || ticketCount <= 0) {
|
||||
ticketCount = 1;
|
||||
}
|
||||
|
||||
// TODO: 这里需要实现实际的奖励发放逻辑
|
||||
// 1. 记录用户已领取该奖励
|
||||
// 2. 发放奖励到用户账户
|
||||
// 3. 发送通知等
|
||||
List<Long> ticketIds = new ArrayList<>();
|
||||
for (int i = 0; i < ticketCount; i++) {
|
||||
Long ticketId = ResponseAssert.requiredSuccess(
|
||||
lotteryTicketClient.addTicket(
|
||||
cmd.getReqUserId(),
|
||||
1,
|
||||
"ACTIVITY_REWARD",
|
||||
cmd.getRuleId().toString()
|
||||
)
|
||||
);
|
||||
ticketIds.add(ticketId);
|
||||
}
|
||||
|
||||
UserActivityRewardClaim claim = new UserActivityRewardClaim()
|
||||
.setUserId(cmd.getReqUserId())
|
||||
.setActivityId(cmd.getActivityId())
|
||||
.setRuleId(cmd.getRuleId())
|
||||
.setActivityType(cmd.getActivityType())
|
||||
.setStatus(1)
|
||||
.setLotteryTicketIds(String.join(",", ticketIds.stream().map(String::valueOf).toArray(String[]::new)))
|
||||
.setCreateTime(TimestampUtils.now())
|
||||
.setUpdateTime(TimestampUtils.now());
|
||||
|
||||
userActivityRewardClaimDAO.insert(claim);
|
||||
|
||||
return new ClaimRewardResultCO()
|
||||
.setSuccess(true)
|
||||
.setMessage("Successfully claimed");
|
||||
.setLotteryTicketIds(ticketIds);
|
||||
}
|
||||
|
||||
private BigDecimal parseRequiredAmount(String jsonData) {
|
||||
@ -90,8 +130,35 @@ public class ClaimActivityRewardExe {
|
||||
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
log.error("解析jsonData失败: {}", jsonData, e);
|
||||
log.error("parse jsonData error: {}", jsonData, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Integer parseTicketCount(String jsonData) {
|
||||
if (StrUtil.isBlank(jsonData)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
Map<String, Object> dataMap = JacksonUtils.readValue(jsonData, Map.class);
|
||||
Object ticketCount = dataMap.get("ticketCount");
|
||||
if (Objects.isNull(ticketCount)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (ticketCount instanceof Number) {
|
||||
return ((Number) ticketCount).intValue();
|
||||
}
|
||||
|
||||
if (ticketCount instanceof String) {
|
||||
return Integer.parseInt((String) ticketCount);
|
||||
}
|
||||
|
||||
return 1;
|
||||
} catch (Exception e) {
|
||||
log.error("parse ticketCount error: {}", jsonData, e);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,6 +7,7 @@ import com.red.circle.other.app.dto.clientobject.activity.ClaimRewardResultCO;
|
||||
import com.red.circle.other.app.dto.cmd.activity.ActivityRewardConfigCmd;
|
||||
import com.red.circle.other.app.dto.cmd.activity.ClaimActivityRewardCmd;
|
||||
import com.red.circle.other.app.service.activity.ActivityRewardConfigService;
|
||||
import com.red.circle.other.app.util.DistributedLockUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@ -21,6 +22,9 @@ public class ActivityRewardConfigServiceImpl implements ActivityRewardConfigServ
|
||||
|
||||
private final ActivityRewardConfigQryExe activityRewardConfigQryExe;
|
||||
private final ClaimActivityRewardExe claimActivityRewardExe;
|
||||
private final DistributedLockUtil distributedLockUtil;
|
||||
|
||||
private static final String CLAIM_LOCK_PREFIX = "activity:reward:claim:lock";
|
||||
|
||||
@Override
|
||||
public List<ActivityRewardConfigCO> listRewardConfigs(ActivityRewardConfigCmd cmd) {
|
||||
@ -29,6 +33,15 @@ public class ActivityRewardConfigServiceImpl implements ActivityRewardConfigServ
|
||||
|
||||
@Override
|
||||
public ClaimRewardResultCO claimReward(ClaimActivityRewardCmd cmd) {
|
||||
return claimActivityRewardExe.execute(cmd);
|
||||
String lockKey = DistributedLockUtil.buildLockKey(
|
||||
CLAIM_LOCK_PREFIX,
|
||||
cmd.getReqUserId(),
|
||||
cmd.getRuleId()
|
||||
);
|
||||
|
||||
return distributedLockUtil.executeWithLock(
|
||||
lockKey,
|
||||
() -> claimActivityRewardExe.execute(cmd)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,6 +37,8 @@ public class ActivityRewardConfigCO implements Serializable {
|
||||
|
||||
private Boolean shelfStatus;
|
||||
|
||||
private Integer claimStatus;
|
||||
|
||||
private List<ActivityRewardPropsCO> rewardProps;
|
||||
|
||||
@Data
|
||||
|
||||
@ -4,6 +4,7 @@ import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 领取奖励结果CO
|
||||
@ -14,5 +15,5 @@ public class ClaimRewardResultCO implements Serializable {
|
||||
|
||||
private Boolean success;
|
||||
|
||||
private String message;
|
||||
private List<Long> lotteryTicketIds;
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
package com.red.circle.other.infra.database.rds.dao.activity;
|
||||
|
||||
import com.red.circle.framework.mybatis.dao.BaseDAO;
|
||||
import com.red.circle.other.infra.database.rds.entity.activity.UserActivityRewardClaim;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 用户活动奖励领取记录DAO
|
||||
*/
|
||||
@Mapper
|
||||
public interface UserActivityRewardClaimDAO extends BaseDAO<UserActivityRewardClaim> {
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
package com.red.circle.other.infra.database.rds.entity.activity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* 用户活动奖励领取记录
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@TableName("user_activity_reward_claim")
|
||||
public class UserActivityRewardClaim implements Serializable {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private Long userId;
|
||||
|
||||
private Long activityId;
|
||||
|
||||
private Long ruleId;
|
||||
|
||||
private String activityType;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String lotteryTicketIds;
|
||||
|
||||
private Timestamp createTime;
|
||||
|
||||
private Timestamp updateTime;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user