拉新奖励逻辑更新
This commit is contained in:
parent
7cbcef2772
commit
e2849d2cca
@ -1,5 +1,6 @@
|
|||||||
package com.red.circle.other.domain.gateway.user.ability;
|
package com.red.circle.other.domain.gateway.user.ability;
|
||||||
|
|
||||||
|
import com.red.circle.other.domain.model.user.RechargeCommissionResult;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -15,9 +16,9 @@ public interface InviteUserGateway {
|
|||||||
* @param rechargeAmount 充值金额
|
* @param rechargeAmount 充值金额
|
||||||
* @param sysOrigin 系统
|
* @param sysOrigin 系统
|
||||||
* @param inviteUserId 被邀请人(充值人)
|
* @param inviteUserId 被邀请人(充值人)
|
||||||
|
* @return 佣金处理结果,无邀请关系时返回null
|
||||||
*/
|
*/
|
||||||
void getRechargeCommission(BigDecimal rechargeAmount, String sysOrigin,
|
RechargeCommissionResult getRechargeCommission(BigDecimal rechargeAmount, String sysOrigin,
|
||||||
Long inviteUserId);
|
Long inviteUserId);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,29 @@
|
|||||||
|
package com.red.circle.other.domain.model.user;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邀请佣金处理结果.
|
||||||
|
*
|
||||||
|
* @author tf
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class RechargeCommissionResult {
|
||||||
|
|
||||||
|
/** 邀请人(A)的userId. */
|
||||||
|
private Long inviterUserId;
|
||||||
|
|
||||||
|
/** 被邀请人(B)的userId. */
|
||||||
|
private Long inviteeUserId;
|
||||||
|
|
||||||
|
/** 被邀请人累计充值金额(Redis累计,用于档位判断). */
|
||||||
|
private BigDecimal inviteeTotalRecharge;
|
||||||
|
|
||||||
|
/** 系统来源. */
|
||||||
|
private String sysOrigin;
|
||||||
|
|
||||||
|
/** 被邀请人是否为7天内新用户. */
|
||||||
|
private boolean newUser;
|
||||||
|
|
||||||
|
}
|
||||||
@ -13,7 +13,12 @@ public enum UserOneTimeTaskTypeEnum {
|
|||||||
/**
|
/**
|
||||||
* 首次充值.
|
* 首次充值.
|
||||||
*/
|
*/
|
||||||
FIRST_CHARGE;
|
FIRST_CHARGE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 邀请奖励.
|
||||||
|
*/
|
||||||
|
INVITE_REWARD;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,9 @@ package com.red.circle.other.infra.gateway.user;
|
|||||||
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
|
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||||
|
import com.red.circle.component.redis.service.RedisService;
|
||||||
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||||
|
import com.red.circle.other.domain.model.user.RechargeCommissionResult;
|
||||||
import com.red.circle.other.domain.model.user.UserProfile;
|
import com.red.circle.other.domain.model.user.UserProfile;
|
||||||
import com.red.circle.other.domain.ranking.RankingActivityType;
|
import com.red.circle.other.domain.ranking.RankingActivityType;
|
||||||
import com.red.circle.other.domain.ranking.RankingCycleType;
|
import com.red.circle.other.domain.ranking.RankingCycleType;
|
||||||
@ -11,26 +13,13 @@ import com.red.circle.other.domain.ranking.RankingDimension;
|
|||||||
import com.red.circle.other.infra.database.mongo.entity.activity.RankingActivityRecord;
|
import com.red.circle.other.infra.database.mongo.entity.activity.RankingActivityRecord;
|
||||||
import com.red.circle.other.infra.database.rds.dao.user.user.UserInviteUserDAO;
|
import com.red.circle.other.infra.database.rds.dao.user.user.UserInviteUserDAO;
|
||||||
import com.red.circle.other.infra.database.rds.entity.user.user.InviteUserRechargeCommission;
|
import com.red.circle.other.infra.database.rds.entity.user.user.InviteUserRechargeCommission;
|
||||||
import com.red.circle.other.infra.database.rds.entity.user.user.OneTimeTask;
|
|
||||||
import com.red.circle.other.infra.database.rds.entity.user.user.UserInviteUser;
|
import com.red.circle.other.infra.database.rds.entity.user.user.UserInviteUser;
|
||||||
import com.red.circle.other.infra.database.rds.service.user.user.OneTimeTaskService;
|
|
||||||
import com.red.circle.other.infra.gateway.RankingActivityGateway;
|
|
||||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
|
||||||
import com.red.circle.tool.core.date.TimestampUtils;
|
|
||||||
import com.red.circle.other.domain.gateway.user.ability.InviteUserGateway;
|
|
||||||
import com.red.circle.other.infra.database.cache.service.user.UserInviteCacheService;
|
|
||||||
import com.red.circle.other.infra.database.rds.entity.user.user.InviteUserRegister;
|
|
||||||
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRechargeCommissionService;
|
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRechargeCommissionService;
|
||||||
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRegisterService;
|
|
||||||
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserSummaryService;
|
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserSummaryService;
|
||||||
import java.math.BigDecimal;
|
import com.red.circle.other.infra.database.cache.service.user.UserInviteCacheService;
|
||||||
import java.math.RoundingMode;
|
import com.red.circle.other.infra.gateway.RankingActivityGateway;
|
||||||
import java.sql.Timestamp;
|
import com.red.circle.other.domain.gateway.user.ability.InviteUserGateway;
|
||||||
import java.time.Duration;
|
import com.red.circle.tool.core.date.TimestampUtils;
|
||||||
import java.time.LocalDateTime;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
|
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
|
||||||
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
|
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
|
||||||
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
|
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
|
||||||
@ -39,6 +28,15 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 被邀请的用户充值,邀请人获得佣金处理 实现.
|
* 被邀请的用户充值,邀请人获得佣金处理 实现.
|
||||||
*
|
*
|
||||||
@ -49,61 +47,57 @@ import org.springframework.stereotype.Component;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class InviteUserGatewayImpl implements InviteUserGateway {
|
public class InviteUserGatewayImpl implements InviteUserGateway {
|
||||||
|
|
||||||
|
private static final String INVITE_RECHARGE_TOTAL_KEY = "invite:recharge:total:%d:%d";
|
||||||
|
private static final long INVITE_RECHARGE_TOTAL_EXPIRE_DAYS = 30L;
|
||||||
|
|
||||||
private final WalletGoldClient walletGoldClient;
|
private final WalletGoldClient walletGoldClient;
|
||||||
private final UserInviteCacheService userInviteCacheService;
|
private final UserInviteCacheService userInviteCacheService;
|
||||||
private final InviteUserSummaryService inviteUserSummaryService;
|
private final InviteUserSummaryService inviteUserSummaryService;
|
||||||
private final UserInviteUserDAO userInviteUserDAO;
|
private final UserInviteUserDAO userInviteUserDAO;
|
||||||
private final UserProfileGateway userProfileGateway;
|
private final UserProfileGateway userProfileGateway;
|
||||||
private final InviteUserRechargeCommissionService inviteUserRechargeCommissionService;
|
private final InviteUserRechargeCommissionService inviteUserRechargeCommissionService;
|
||||||
private final OneTimeTaskService oneTimeTaskService;
|
|
||||||
private final RankingActivityGateway rankingActivityGateway;
|
private final RankingActivityGateway rankingActivityGateway;
|
||||||
|
private final RedisService redisService;
|
||||||
|
|
||||||
/**
|
|
||||||
* 被邀请人充值邀请人获得佣金
|
|
||||||
*
|
|
||||||
* @param rechargeAmount 充值金额
|
|
||||||
* @param sysOrigin 系统
|
|
||||||
* @param inviteUserId 被邀请人(充值人)
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public void getRechargeCommission(BigDecimal rechargeAmount, String sysOrigin,
|
public RechargeCommissionResult getRechargeCommission(BigDecimal rechargeAmount, String sysOrigin,
|
||||||
Long inviteUserId) {
|
Long inviteUserId) {
|
||||||
|
|
||||||
//根据被邀请人获得邀请人
|
//根据被邀请人获得邀请人
|
||||||
UserInviteUser userInviteUser = getByInviteUserId(inviteUserId);
|
UserInviteUser userInviteUser = getByInviteUserId(inviteUserId);
|
||||||
if (Objects.isNull(userInviteUser)) {
|
if (Objects.isNull(userInviteUser)) {
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//能够赚取佣金的天数
|
//能够赚取佣金的天数
|
||||||
Integer commissionDays = getCommissionDays(sysOrigin);
|
Integer commissionDays = getCommissionDays(sysOrigin);
|
||||||
if (Objects.isNull(commissionDays)) {
|
if (Objects.isNull(commissionDays)) {
|
||||||
log.info("能够赚取佣金的天数 => null, inviteUserId:{}", inviteUserId);
|
log.info("能够赚取佣金的天数 => null, inviteUserId:{}", inviteUserId);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
//邀请时间 + 有效天数 > 当前时间 则可以继续获得佣金。
|
|
||||||
Timestamp limitedTime = getLimitedTime(userInviteUser, commissionDays);
|
Timestamp limitedTime = getLimitedTime(userInviteUser, commissionDays);
|
||||||
if (limitedTime.compareTo(TimestampUtils.now()) < 0) {
|
if (limitedTime.compareTo(TimestampUtils.now()) < 0) {
|
||||||
log.info("邀请时间 + 有效天数 < 当前时间, inviteUserId:{}", inviteUserId);
|
log.info("邀请时间 + 有效天数 < 当前时间, inviteUserId:{}", inviteUserId);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//获得佣金比例
|
Double commissionRate = getCommissionRate(sysOrigin);
|
||||||
Double commissionRate = getCommissionRate(sysOrigin, userInviteUser.getInviteUserId());
|
|
||||||
if (Objects.isNull(commissionRate)) {
|
if (Objects.isNull(commissionRate)) {
|
||||||
log.info("获得佣金比例 => null, inviteUserId:{}", inviteUserId);
|
log.info("获得佣金比例 => null, inviteUserId:{}", inviteUserId);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
//获得的佣金 = 糖果数 * 佣金比例
|
//获得的佣金 = 糖果数 * 佣金比例
|
||||||
BigDecimal commission = getCommission(rechargeAmount, commissionRate);
|
BigDecimal commission = getCommission(rechargeAmount, commissionRate);
|
||||||
if (commission.compareTo(BigDecimal.ZERO) <= 0) {
|
if (commission.compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
log.info("糖果数 * 佣金比例 <= 0, inviteUserId:{}", inviteUserId);
|
log.info("糖果数 * 佣金比例 <= 0, inviteUserId:{}", inviteUserId);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
inviteUserSummaryService.incrCommission(userInviteUser.getUserId(), commission);
|
inviteUserSummaryService.incrCommission(userInviteUser.getUserId(), commission);
|
||||||
inviteUserRechargeCommissionService.add(sysOrigin, userInviteUser.getUserId(), userInviteUser.getInviteUserId(), commission);
|
inviteUserRechargeCommissionService.add(sysOrigin, userInviteUser.getUserId(),
|
||||||
|
userInviteUser.getInviteUserId(), commission);
|
||||||
|
|
||||||
// 累计邀请人数:判断inviteUserRechargeCommissionService里是否已有该被邀请人的记录
|
// 累计邀请人数:判断inviteUserRechargeCommissionService里是否已有该被邀请人的记录
|
||||||
// 查询该被邀请人在此之前是否有充值记录
|
// 查询该被邀请人在此之前是否有充值记录
|
||||||
@ -114,7 +108,7 @@ public class InviteUserGatewayImpl implements InviteUserGateway {
|
|||||||
|
|
||||||
// 如果记录数 < 1,说明是首次充值(当前这条刚插入),才累计邀请人数+1
|
// 如果记录数 < 1,说明是首次充值(当前这条刚插入),才累计邀请人数+1
|
||||||
if (recordCount < 1) {
|
if (recordCount < 1) {
|
||||||
log.info("被邀请人首次充值,累计邀请人数+1, inviterUserId:{}, inviteUserId:{}",
|
log.info("被邀请人首次充值,累计邀请人数+1, inviterUserId:{}, inviteeUserId:{}",
|
||||||
userInviteUser.getUserId(), userInviteUser.getInviteUserId());
|
userInviteUser.getUserId(), userInviteUser.getInviteUserId());
|
||||||
inviteUserSummaryService.incrUser(userInviteUser.getUserId(), 1);
|
inviteUserSummaryService.incrUser(userInviteUser.getUserId(), 1);
|
||||||
}
|
}
|
||||||
@ -122,21 +116,39 @@ public class InviteUserGatewayImpl implements InviteUserGateway {
|
|||||||
awardCommission(sysOrigin, userInviteUser.getUserId(), commission, userInviteUser.getInviteUserId());
|
awardCommission(sysOrigin, userInviteUser.getUserId(), commission, userInviteUser.getInviteUserId());
|
||||||
|
|
||||||
recordRanking(userInviteUser.getUserId(), commission.longValue());
|
recordRanking(userInviteUser.getUserId(), commission.longValue());
|
||||||
|
|
||||||
|
BigDecimal totalRecharge = accumulateRecharge(userInviteUser.getUserId(), inviteUserId, rechargeAmount);
|
||||||
|
|
||||||
|
RechargeCommissionResult result = new RechargeCommissionResult();
|
||||||
|
result.setInviterUserId(userInviteUser.getUserId());
|
||||||
|
result.setInviteeUserId(inviteUserId);
|
||||||
|
result.setInviteeTotalRecharge(totalRecharge);
|
||||||
|
result.setSysOrigin(sysOrigin);
|
||||||
|
result.setNewUser(isNewUserWithinDays(inviteUserId, 7));
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recordRanking(Long userId, Long quantity) {
|
private BigDecimal accumulateRecharge(Long inviterUserId, Long inviteeUserId, BigDecimal rechargeAmount) {
|
||||||
RankingActivityRecord record = new RankingActivityRecord();
|
String key = String.format(INVITE_RECHARGE_TOTAL_KEY, inviterUserId, inviteeUserId);
|
||||||
record.setSysOrigin(SysOriginPlatformEnum.LIKEI.name());
|
Long total = redisService.increment(key, rechargeAmount.longValue());
|
||||||
record.setUserId(userId);
|
if (total != null && total <= rechargeAmount.longValue()) {
|
||||||
record.setUserSex(1);
|
redisService.expire(key, INVITE_RECHARGE_TOTAL_EXPIRE_DAYS, TimeUnit.DAYS);
|
||||||
record.setActivityType(RankingActivityType.INVITE);
|
|
||||||
record.setCycleType(RankingCycleType.WEEKLY);
|
|
||||||
record.setCycleKey(ZonedDateTimeAsiaRiyadhUtils.nowWeekMondayToInt().toString());
|
|
||||||
record.setDimension(RankingDimension.CONSUME_AMOUNT);
|
|
||||||
record.setExpiredTime(new Timestamp(System.currentTimeMillis() + 30L * 24 * 60 * 60 * 1000));
|
|
||||||
// 累计数据
|
|
||||||
rankingActivityGateway.accumulateRankingData(record, quantity);
|
|
||||||
}
|
}
|
||||||
|
return total != null ? BigDecimal.valueOf(total) : rechargeAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void recordRanking(Long userId, Long quantity) {
|
||||||
|
RankingActivityRecord record = new RankingActivityRecord();
|
||||||
|
record.setSysOrigin(SysOriginPlatformEnum.LIKEI.name());
|
||||||
|
record.setUserId(userId);
|
||||||
|
record.setUserSex(1);
|
||||||
|
record.setActivityType(RankingActivityType.INVITE);
|
||||||
|
record.setCycleType(RankingCycleType.WEEKLY);
|
||||||
|
record.setCycleKey(ZonedDateTimeAsiaRiyadhUtils.nowWeekMondayToInt().toString());
|
||||||
|
record.setDimension(RankingDimension.CONSUME_AMOUNT);
|
||||||
|
record.setExpiredTime(new Timestamp(System.currentTimeMillis() + 30L * 24 * 60 * 60 * 1000));
|
||||||
|
rankingActivityGateway.accumulateRankingData(record, quantity);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 奖励佣金
|
* 奖励佣金
|
||||||
@ -164,18 +176,15 @@ public class InviteUserGatewayImpl implements InviteUserGateway {
|
|||||||
.setScale(0, RoundingMode.DOWN);
|
.setScale(0, RoundingMode.DOWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Double getCommissionRate(String sysOrigin, Long userId) {
|
private Double getCommissionRate(String sysOrigin) {
|
||||||
Double commissionRate = userInviteCacheService.getCommissionRate(SysOriginPlatformEnum.valueOf(sysOrigin));
|
return userInviteCacheService.getCommissionRate(SysOriginPlatformEnum.valueOf(sysOrigin));
|
||||||
|
}
|
||||||
|
|
||||||
UserProfile userProfile = userProfileGateway.getByUserId(userId);
|
/** 判断用户是否为注册N天内的新用户 */
|
||||||
Duration duration = Duration.between(userProfile.getCreateTime().toLocalDateTime(), LocalDateTime.now());
|
private boolean isNewUserWithinDays(Long userId, int days) {
|
||||||
if (duration.toDays() < 7) {
|
UserProfile userProfile = userProfileGateway.getByUserId(userId);
|
||||||
OneTimeTask oneTimeTask = oneTimeTaskService.queryCompletedFirstCharge(userId, sysOrigin);
|
Duration duration = Duration.between(userProfile.getCreateTime().toLocalDateTime(), LocalDateTime.now());
|
||||||
if (Objects.isNull(oneTimeTask)) {
|
return duration.toDays() < days;
|
||||||
commissionRate += 0.03;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return commissionRate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private UserInviteUser getByInviteUserId(Long inviteUserId) {
|
private UserInviteUser getByInviteUserId(Long inviteUserId) {
|
||||||
@ -196,13 +205,11 @@ public class InviteUserGatewayImpl implements InviteUserGateway {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Integer getCommissionDays(String sysOrigin) {
|
private Integer getCommissionDays(String sysOrigin) {
|
||||||
return userInviteCacheService
|
return userInviteCacheService.getCommissionDays(SysOriginPlatformEnum.valueOf(sysOrigin));
|
||||||
.getCommissionDays(SysOriginPlatformEnum.valueOf(sysOrigin));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Timestamp getLimitedTime(UserInviteUser userInviteUser, Integer commissionDays) {
|
private Timestamp getLimitedTime(UserInviteUser userInviteUser, Integer commissionDays) {
|
||||||
return TimestampUtils
|
return TimestampUtils.dateTimestampPlusDays(userInviteUser.getCreateTime().toLocalDateTime(), commissionDays);
|
||||||
.dateTimestampPlusDays(userInviteUser.getCreateTime().toLocalDateTime(), commissionDays);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,8 @@ package com.red.circle.other.app.inner.service.user.user.impl;
|
|||||||
|
|
||||||
import com.google.common.base.Throwables;
|
import com.google.common.base.Throwables;
|
||||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||||
|
import com.red.circle.common.business.enums.SendPropsOrigin;
|
||||||
|
import com.red.circle.component.redis.service.RedisService;
|
||||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||||
import com.red.circle.framework.dto.PageResult;
|
import com.red.circle.framework.dto.PageResult;
|
||||||
@ -9,14 +11,19 @@ import com.red.circle.framework.mybatis.convertor.MybatisConvertor;
|
|||||||
import com.red.circle.other.app.inner.convertor.user.UserInviteInnerConvertor;
|
import com.red.circle.other.app.inner.convertor.user.UserInviteInnerConvertor;
|
||||||
import com.red.circle.other.app.inner.service.user.user.InviteUserClientService;
|
import com.red.circle.other.app.inner.service.user.user.InviteUserClientService;
|
||||||
import com.red.circle.other.domain.gateway.user.ability.InviteUserGateway;
|
import com.red.circle.other.domain.gateway.user.ability.InviteUserGateway;
|
||||||
|
import com.red.circle.other.domain.model.user.RechargeCommissionResult;
|
||||||
import com.red.circle.other.infra.database.cache.service.user.UserInviteCacheService;
|
import com.red.circle.other.infra.database.cache.service.user.UserInviteCacheService;
|
||||||
|
import com.red.circle.other.infra.database.rds.entity.user.user.OneTimeTask;
|
||||||
import com.red.circle.other.infra.database.rds.query.user.InviteUserQry;
|
import com.red.circle.other.infra.database.rds.query.user.InviteUserQry;
|
||||||
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRechargeCommissionService;
|
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRechargeCommissionService;
|
||||||
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRegisterService;
|
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRegisterService;
|
||||||
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRewardRecordService;
|
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserRewardRecordService;
|
||||||
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserSummaryService;
|
import com.red.circle.other.infra.database.rds.service.user.user.InviteUserSummaryService;
|
||||||
import com.red.circle.tool.core.date.TimestampUtils;
|
import com.red.circle.other.infra.database.rds.service.user.user.OneTimeTaskService;
|
||||||
import com.red.circle.tool.core.text.StringUtils;
|
import com.red.circle.other.infra.enums.user.user.UserOneTimeTaskTypeEnum;
|
||||||
|
import com.red.circle.other.inner.endpoint.activity.PropsActivityClient;
|
||||||
|
import com.red.circle.other.inner.endpoint.sys.EnumConfigClient;
|
||||||
|
import com.red.circle.other.inner.model.cmd.activity.SendActivityRewardCmd;
|
||||||
import com.red.circle.other.inner.model.cmd.user.InviteUserQryCmd;
|
import com.red.circle.other.inner.model.cmd.user.InviteUserQryCmd;
|
||||||
import com.red.circle.other.inner.model.cmd.user.SysInviteUserConfigCmd;
|
import com.red.circle.other.inner.model.cmd.user.SysInviteUserConfigCmd;
|
||||||
import com.red.circle.other.inner.model.cmd.user.UserInviteRewardQryCmd;
|
import com.red.circle.other.inner.model.cmd.user.UserInviteRewardQryCmd;
|
||||||
@ -26,13 +33,23 @@ import com.red.circle.other.inner.model.dto.user.InviteUserRewardRecordDTO;
|
|||||||
import com.red.circle.other.inner.model.dto.user.InviteUserSummaryDTO;
|
import com.red.circle.other.inner.model.dto.user.InviteUserSummaryDTO;
|
||||||
import com.red.circle.other.inner.model.dto.user.PageInviteUserRegisterDTO;
|
import com.red.circle.other.inner.model.dto.user.PageInviteUserRegisterDTO;
|
||||||
import com.red.circle.other.inner.model.dto.user.SysInviteUserConfigDTO;
|
import com.red.circle.other.inner.model.dto.user.SysInviteUserConfigDTO;
|
||||||
import java.math.BigDecimal;
|
import com.red.circle.tool.core.date.TimestampUtils;
|
||||||
import java.util.List;
|
import com.red.circle.tool.core.sequence.IdWorkerUtils;
|
||||||
import java.util.Objects;
|
import com.red.circle.tool.core.text.StringUtils;
|
||||||
|
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
|
||||||
|
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
|
||||||
|
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 邀请用户.
|
* 邀请用户.
|
||||||
*
|
*
|
||||||
@ -43,6 +60,21 @@ import org.springframework.stereotype.Service;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class InviteUserClientServiceImpl implements InviteUserClientService {
|
public class InviteUserClientServiceImpl implements InviteUserClientService {
|
||||||
|
|
||||||
|
// 档位阈值
|
||||||
|
private static final long TIER1_THRESHOLD = 10_000L;
|
||||||
|
private static final long TIER2_THRESHOLD = 50_000L;
|
||||||
|
private static final long TIER3_THRESHOLD = 100_000L;
|
||||||
|
|
||||||
|
// 档位道具id
|
||||||
|
private static final long TIER1_PROPS_ID = 2029448725407711234L;
|
||||||
|
private static final long TIER2_PROPS_ID = 2029449081176965121L;
|
||||||
|
private static final long TIER3_PROPS_ID = 2029449364032438273L;
|
||||||
|
|
||||||
|
// 档位金币奖励
|
||||||
|
private static final long TIER1_GOLD = 2000L;
|
||||||
|
private static final long TIER2_GOLD = 5000L;
|
||||||
|
private static final long TIER3_GOLD = 5000L;
|
||||||
|
|
||||||
private final InviteUserGateway inviteUserGateway;
|
private final InviteUserGateway inviteUserGateway;
|
||||||
private final UserInviteCacheService userInviteCacheService;
|
private final UserInviteCacheService userInviteCacheService;
|
||||||
private final UserInviteInnerConvertor userInviteInnerConvertor;
|
private final UserInviteInnerConvertor userInviteInnerConvertor;
|
||||||
@ -50,17 +82,99 @@ public class InviteUserClientServiceImpl implements InviteUserClientService {
|
|||||||
private final InviteUserRegisterService inviteUserRegisterService;
|
private final InviteUserRegisterService inviteUserRegisterService;
|
||||||
private final InviteUserRewardRecordService inviteUserRewardRecordService;
|
private final InviteUserRewardRecordService inviteUserRewardRecordService;
|
||||||
private final InviteUserRechargeCommissionService rechargeCommissionService;
|
private final InviteUserRechargeCommissionService rechargeCommissionService;
|
||||||
|
private final PropsActivityClient propsActivityClient;
|
||||||
|
private final WalletGoldClient walletGoldClient;
|
||||||
|
private final OneTimeTaskService oneTimeTaskService;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void processRechargeCommission(BigDecimal rechargeAmount, String sysOrigin,
|
public void processRechargeCommission(BigDecimal rechargeAmount, String sysOrigin,
|
||||||
Long inviteUserId) {
|
Long inviteUserId) {
|
||||||
try {
|
try {
|
||||||
inviteUserGateway.getRechargeCommission(rechargeAmount, sysOrigin, inviteUserId);
|
RechargeCommissionResult result = inviteUserGateway.getRechargeCommission(rechargeAmount, sysOrigin, inviteUserId);
|
||||||
|
if (Objects.isNull(result)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkAndAwardTiers(result);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("被邀请人充值邀请人获得佣金累计错误: {}", Throwables.getStackTraceAsString(e));
|
log.error("被邀请人充值邀请人获得佣金累计错误: {}", Throwables.getStackTraceAsString(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据累计充值金额检查并发放档位奖励
|
||||||
|
*/
|
||||||
|
private void checkAndAwardTiers(RechargeCommissionResult result) {
|
||||||
|
if (!result.isNewUser()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
long total = result.getInviteeTotalRecharge().longValue();
|
||||||
|
|
||||||
|
if (total >= TIER3_THRESHOLD) {
|
||||||
|
tryAwardTier(result, 3, TIER3_PROPS_ID, TIER3_GOLD);
|
||||||
|
tryAwardTier(result, 2, TIER2_PROPS_ID, TIER2_GOLD);
|
||||||
|
tryAwardTier(result, 1, TIER1_PROPS_ID, TIER1_GOLD);
|
||||||
|
} else if (total >= TIER2_THRESHOLD) {
|
||||||
|
tryAwardTier(result, 2, TIER2_PROPS_ID, TIER2_GOLD);
|
||||||
|
tryAwardTier(result, 1, TIER1_PROPS_ID, TIER1_GOLD);
|
||||||
|
} else if (total >= TIER1_THRESHOLD) {
|
||||||
|
tryAwardTier(result, 1, TIER1_PROPS_ID, TIER1_GOLD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 尝试发放指定档位奖励(幂等)
|
||||||
|
* 金币发给邀请人A,道具发给被邀请人B
|
||||||
|
*/
|
||||||
|
private void tryAwardTier(RechargeCommissionResult result, int tier, long propsId, long gold) {
|
||||||
|
String taskType = UserOneTimeTaskTypeEnum.INVITE_REWARD.name() + "_" + tier;
|
||||||
|
|
||||||
|
OneTimeTask alreadyRewarded = oneTimeTaskService.query()
|
||||||
|
.eq(OneTimeTask::getUserId, result.getInviterUserId())
|
||||||
|
.eq(OneTimeTask::getSysOrigin, result.getSysOrigin())
|
||||||
|
.eq(OneTimeTask::getTaskType, taskType)
|
||||||
|
.last("LIMIT 1")
|
||||||
|
.getOne();
|
||||||
|
|
||||||
|
if (alreadyRewarded != null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.info("发放邀请奖励档位{}: inviterUserId={}, inviteeUserId={}", tier,
|
||||||
|
result.getInviterUserId(), result.getInviteeUserId());
|
||||||
|
|
||||||
|
// 写入记录(幂等保证)
|
||||||
|
oneTimeTaskService.save(new OneTimeTask()
|
||||||
|
.setUserId(result.getInviterUserId())
|
||||||
|
.setSysOrigin(result.getSysOrigin())
|
||||||
|
.setTaskType(taskType)
|
||||||
|
.setRewardQuantity(BigDecimal.valueOf(gold))
|
||||||
|
.setAwardStatus(Boolean.TRUE)
|
||||||
|
);
|
||||||
|
|
||||||
|
// 金币奖励发给邀请人A
|
||||||
|
walletGoldClient.changeBalance(GoldReceiptCmd.builder()
|
||||||
|
.appIncome()
|
||||||
|
.userId(result.getInviterUserId())
|
||||||
|
.eventId(result.getInviteeUserId())
|
||||||
|
.sysOrigin(result.getSysOrigin())
|
||||||
|
.origin(GoldOrigin.INVITE_USER_REWARDS)
|
||||||
|
.originDescribe(GoldOrigin.INVITE_USER_REWARDS.getDesc())
|
||||||
|
.amount(BigDecimal.valueOf(gold))
|
||||||
|
.build());
|
||||||
|
|
||||||
|
// 道具奖励发给被邀请人B
|
||||||
|
propsActivityClient.sendActivityReward(new SendActivityRewardCmd()
|
||||||
|
.setTrackId(IdWorkerUtils.getId())
|
||||||
|
.setSysOrigin(SysOriginPlatformEnum.LIKEI)
|
||||||
|
.setAcceptUserId(result.getInviteeUserId())
|
||||||
|
.setSourceGroupId(propsId)
|
||||||
|
.setOrigin(SendPropsOrigin.INVITE_USER_REWARDS)
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<InviteUserRegisterDTO> pageInviteUserRegister(Integer pageNumber, Long userId) {
|
public List<InviteUserRegisterDTO> pageInviteUserRegister(Integer pageNumber, Long userId) {
|
||||||
return userInviteInnerConvertor.toListInviteUserRegisterDTO(
|
return userInviteInnerConvertor.toListInviteUserRegisterDTO(
|
||||||
@ -107,10 +221,8 @@ public class InviteUserClientServiceImpl implements InviteUserClientService {
|
|||||||
.convert(userInviteInnerConvertor::toInviteUserRewardRecordDTO);
|
.convert(userInviteInnerConvertor::toInviteUserRewardRecordDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PageResult<PageInviteUserRegisterDTO> pageInviteUserRegisterAll(InviteUserQryCmd query) {
|
public PageResult<PageInviteUserRegisterDTO> pageInviteUserRegisterAll(InviteUserQryCmd query) {
|
||||||
|
|
||||||
InviteUserQry inviteUserQry = new InviteUserQry();
|
InviteUserQry inviteUserQry = new InviteUserQry();
|
||||||
inviteUserQry.setSysOrigin(query.getSysOrigin());
|
inviteUserQry.setSysOrigin(query.getSysOrigin());
|
||||||
inviteUserQry.setUserId(query.getUserId());
|
inviteUserQry.setUserId(query.getUserId());
|
||||||
@ -128,7 +240,6 @@ public class InviteUserClientServiceImpl implements InviteUserClientService {
|
|||||||
inviteUserQry).convert(userInviteInnerConvertor::toPageInviteUserRegisterDTO);
|
inviteUserQry).convert(userInviteInnerConvertor::toPageInviteUserRegisterDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateConfig(SysInviteUserConfigCmd config) {
|
public void updateConfig(SysInviteUserConfigCmd config) {
|
||||||
ResponseAssert.isFalse(CommonErrorCode.TYPE_IS_NOT_IN_SCOPE,
|
ResponseAssert.isFalse(CommonErrorCode.TYPE_IS_NOT_IN_SCOPE,
|
||||||
@ -141,12 +252,8 @@ public class InviteUserClientServiceImpl implements InviteUserClientService {
|
|||||||
} else {
|
} else {
|
||||||
userInviteCacheService.setCommissionRate(sysOrigin, 0.0);
|
userInviteCacheService.setCommissionRate(sysOrigin, 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 邀请用户规则
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public SysInviteUserConfigDTO getConfig(String sysOrigin) {
|
public SysInviteUserConfigDTO getConfig(String sysOrigin) {
|
||||||
SysInviteUserConfigDTO vo = new SysInviteUserConfigDTO();
|
SysInviteUserConfigDTO vo = new SysInviteUserConfigDTO();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user