新增发送平台红包
This commit is contained in:
parent
375f4ef2c2
commit
3b37929c03
@ -128,7 +128,23 @@ public enum RoomErrorCode implements IResponseErrorCode {
|
||||
/**
|
||||
* 房间已关闭.
|
||||
*/
|
||||
ROOM_CLOSE(9114, "Room close");
|
||||
ROOM_CLOSE(9114, "Room close"),
|
||||
|
||||
/**
|
||||
* 不是房间拥有者
|
||||
*/
|
||||
NOT_ROOM_OWNER(9115, "Not the owner of the room"),
|
||||
|
||||
/**
|
||||
* 房间贡献奖励不存在
|
||||
*/
|
||||
ROOM_CONTRIBUTION_NOT_FOUND(9116, "There is no room contribution reward"),
|
||||
|
||||
/**
|
||||
* 房间贡献奖励未达标
|
||||
*/
|
||||
ROOM_CONTRIBUTION_NOT_COMPLETED(9117, "The room reward has not been completed"),
|
||||
;
|
||||
|
||||
private final int code;
|
||||
private final String message;
|
||||
|
||||
@ -45,21 +45,6 @@ public class RoomContributionActivityRestController extends BaseController {
|
||||
return roomContributionActivityService.getRoomContribution(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 领取奖励(已废弃,请使用 /room-reward/receive).
|
||||
*
|
||||
* @deprecated 请使用新接口 /room-reward/receive
|
||||
* @eo.name 领取奖励(已废弃)
|
||||
* @eo.url /receive
|
||||
* @eo.method post
|
||||
* @eo.request-type json
|
||||
*/
|
||||
@Deprecated
|
||||
@PostMapping("/receive")
|
||||
public void receive(AppRoomIdCmd cmd) {
|
||||
roomContributionActivityService.receive(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询房间奖励信息.
|
||||
*
|
||||
|
||||
@ -8,6 +8,7 @@ import com.red.circle.other.infra.database.mongo.entity.activity.RoomContributio
|
||||
import com.red.circle.other.infra.database.mongo.service.activity.RoomContributionActivityCountService;
|
||||
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||
import com.red.circle.other.inner.asserts.ActivityErrorCode;
|
||||
import com.red.circle.other.inner.asserts.RoomErrorCode;
|
||||
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
|
||||
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
|
||||
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
|
||||
@ -54,7 +55,7 @@ public class ReceiveRoomRewardCmdExe {
|
||||
// 2. 校验用户是否是房主
|
||||
Long userRoomId = roomProfileManagerService.getRoomId(userId);
|
||||
ResponseAssert.isTrue(
|
||||
CommonErrorCode.DATA_ERROR,
|
||||
RoomErrorCode.NOT_ROOM_OWNER,
|
||||
Objects.equals(userRoomId, Long.parseLong(roomId))
|
||||
);
|
||||
|
||||
|
||||
@ -4,15 +4,17 @@ import com.red.circle.other.app.dto.clientobject.activity.room.RoomRewardInfoCO;
|
||||
import com.red.circle.other.app.enums.RoomRewardLevelEnum;
|
||||
import com.red.circle.other.infra.database.mongo.entity.activity.RoomContributionActivityCount;
|
||||
import com.red.circle.other.infra.database.mongo.service.activity.RoomContributionActivityCountService;
|
||||
import com.red.circle.other.infra.utils.ZonedDateTimeUtils;
|
||||
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.*;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.time.temporal.TemporalAdjusters;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@ -50,18 +52,11 @@ public class RoomRewardInfoQryExe {
|
||||
/**
|
||||
* 计算到下周一沙特时间0点的倒计时
|
||||
*/
|
||||
private RoomRewardInfoCO.CountdownCO calculateCountdown() {
|
||||
private Timestamp calculateCountdown() {
|
||||
ZonedDateTime now = ZonedDateTimeAsiaRiyadhUtils.now();
|
||||
ZonedDateTime nextMondayZoned = now.plusDays(7 - (now.getDayOfWeek().getValue() - 1));
|
||||
|
||||
Duration duration = Duration.between(now, nextMondayZoned);
|
||||
RoomRewardInfoCO.CountdownCO countdown = new RoomRewardInfoCO.CountdownCO();
|
||||
countdown.setDays(duration.toDays());
|
||||
countdown.setHours(duration.toHours());
|
||||
countdown.setMinutes(duration.toMinutes());
|
||||
countdown.setSeconds(duration.getSeconds());
|
||||
|
||||
return countdown;
|
||||
ZonedDateTime nextMonday = now.with(TemporalAdjusters.next(DayOfWeek.MONDAY))
|
||||
.withHour(0).withMinute(0).withSecond(0).withNano(0);
|
||||
return Timestamp.from(nextMonday.toInstant());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -6,10 +6,12 @@ import com.red.circle.external.inner.model.cmd.message.BroadcastGroupMsgBodyCmd;
|
||||
import com.red.circle.external.inner.model.cmd.message.CustomGroupMsgBodyCmd;
|
||||
import com.red.circle.external.inner.model.enums.message.GroupMessageTypeEnum;
|
||||
import com.red.circle.framework.core.asserts.ResponseAssert;
|
||||
import com.red.circle.framework.core.response.CommonErrorCode;
|
||||
import com.red.circle.other.app.convertor.RoomRedPacketAppConvertor;
|
||||
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
|
||||
import com.red.circle.other.app.dto.clientobject.RoomRedPacketCO;
|
||||
import com.red.circle.other.app.dto.cmd.SendRoomRedPacketCmd;
|
||||
import com.red.circle.other.app.enums.RoomRewardLevelEnum;
|
||||
import com.red.circle.other.app.util.OfficialNoticeUtils;
|
||||
import com.red.circle.other.domain.gateway.RoomRedPacketGateway;
|
||||
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
|
||||
@ -19,9 +21,13 @@ import com.red.circle.other.domain.redpacket.RoomRedPacketSourceType;
|
||||
import com.red.circle.other.domain.redpacket.RoomRedPacketStatus;
|
||||
import com.red.circle.other.domain.redpacket.RoomRedPacketType;
|
||||
import com.red.circle.other.infra.database.cache.service.other.RoomRedPacketCacheService;
|
||||
import com.red.circle.other.infra.database.mongo.entity.activity.RoomContributionActivityCount;
|
||||
import com.red.circle.other.infra.database.mongo.service.activity.RoomContributionActivityCountService;
|
||||
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||
import com.red.circle.other.inner.asserts.OtherErrorCode;
|
||||
import com.red.circle.other.inner.asserts.RoomErrorCode;
|
||||
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
|
||||
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
|
||||
import com.red.circle.tool.core.sequence.IdWorkerUtils;
|
||||
import com.red.circle.tool.core.tuple.PennyAmount;
|
||||
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
|
||||
@ -36,6 +42,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
@ -54,6 +61,7 @@ public class SendRoomRedPacketCmdExe {
|
||||
private final UserProfileGateway userProfileGateway;
|
||||
private final UserProfileAppConvertor userProfileAppConvertor;
|
||||
private final RoomProfileManagerService roomProfileManagerService;
|
||||
private final RoomContributionActivityCountService roomContributionActivityCountService;
|
||||
|
||||
/**
|
||||
* 执行发红包(用户红包)
|
||||
@ -115,7 +123,7 @@ public class SendRoomRedPacketCmdExe {
|
||||
|
||||
// 参数校验
|
||||
validateParams(cmd);
|
||||
|
||||
|
||||
String packetId = IdWorkerUtils.getIdStr();
|
||||
|
||||
// 计算过期时间
|
||||
@ -126,6 +134,8 @@ public class SendRoomRedPacketCmdExe {
|
||||
RoomRedPacket redPacket = buildRedPacket(cmd, systemUserId, packetId, expireTime, RoomRedPacketSourceType.PLATFORM);
|
||||
roomRedPacketGateway.save(redPacket);
|
||||
|
||||
// 查询上周数据
|
||||
deductRoomContribution(cmd.getRoomId(), cmd.getTotalAmount());
|
||||
|
||||
// 预生成随机金额列表(拼手气红包)
|
||||
List<Long> amounts = generateRandomAmounts(cmd.getTotalAmount(), cmd.getTotalCount());
|
||||
@ -143,7 +153,7 @@ public class SendRoomRedPacketCmdExe {
|
||||
);
|
||||
|
||||
// 发送飘窗通知(平台红包)
|
||||
sendMessage(cmd, packetId);
|
||||
// sendMessage(cmd, packetId);
|
||||
|
||||
log.info("发平台红包成功 packetId={} roomId={} amount={} count={} ",
|
||||
packetId, cmd.getRoomId(), cmd.getTotalAmount(), cmd.getTotalCount());
|
||||
@ -151,6 +161,29 @@ public class SendRoomRedPacketCmdExe {
|
||||
return RoomRedPacketAppConvertor.toCO(redPacket);
|
||||
}
|
||||
|
||||
private void deductRoomContribution(Long roomId, Long totalAmount) {
|
||||
String lastWeekDateNumber = ZonedDateTimeAsiaRiyadhUtils.getLastWeekMonday().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
|
||||
RoomContributionActivityCount lastWeek = findByRoomIdAndDateNumber(roomId, Integer.parseInt(lastWeekDateNumber));
|
||||
ResponseAssert.notNull(RoomErrorCode.ROOM_CONTRIBUTION_NOT_FOUND, lastWeek);
|
||||
|
||||
Long amount = lastWeek.getContributionValue().longValue();
|
||||
RoomRewardLevelEnum level = RoomRewardLevelEnum.getLevelByAmount(amount);
|
||||
ResponseAssert.notNull(RoomErrorCode.ROOM_CONTRIBUTION_NOT_COMPLETED, level);
|
||||
ResponseAssert.isTrue(CommonErrorCode.DATA_ERROR, Objects.equals(totalAmount, level.getRewardCoins()));
|
||||
|
||||
boolean updated = roomContributionActivityCountService.updateRewardCoinsSent(lastWeek.getId());
|
||||
ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE, updated);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据房间ID和日期查询数据
|
||||
*/
|
||||
private RoomContributionActivityCount findByRoomIdAndDateNumber(Long roomId, Integer dateNumber) {
|
||||
return roomContributionActivityCountService
|
||||
.findByRoomIdAndDateNumber(roomId, dateNumber)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送消息通知
|
||||
*/
|
||||
|
||||
@ -1,142 +0,0 @@
|
||||
package com.red.circle.other.app.scheduler;
|
||||
|
||||
import com.red.circle.component.redis.annotation.TaskCacheLock;
|
||||
import com.red.circle.other.infra.database.mongo.entity.activity.RoomContributionActivityCount;
|
||||
import com.red.circle.other.infra.database.mongo.service.activity.RoomContributionActivityCountService;
|
||||
import com.red.circle.other.infra.database.mongo.service.live.RoomProfileManagerService;
|
||||
import com.red.circle.tool.core.collection.CollectionUtils;
|
||||
import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils;
|
||||
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 java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 房间贡献周奖励定时任务
|
||||
* <p>
|
||||
* 沙特时间每周一 0 点执行
|
||||
* </p>
|
||||
*
|
||||
* @author Claude
|
||||
* @since 2025-10-28
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RoomContributionWeeklyRewardTask {
|
||||
|
||||
private final RoomContributionActivityCountService roomContributionActivityCountService;
|
||||
private final WalletGoldClient walletGoldClient;
|
||||
private final RoomProfileManagerService roomProfileManagerService;
|
||||
|
||||
/**
|
||||
* 金币奖励比例(上周贡献金额的比例)
|
||||
*/
|
||||
private static final BigDecimal REWARD_RATIO = new BigDecimal("0.05");
|
||||
|
||||
/**
|
||||
* 沙特时间每周一 0 点执行
|
||||
* cron: 秒 分 时 日 月 周
|
||||
* Asia/Riyadh 时区(UTC+3)
|
||||
*/
|
||||
@Scheduled(cron = "0 0 0 * * MON", zone = "Asia/Riyadh")
|
||||
@TaskCacheLock(key = "ROOM_CONTRIBUTION_REWARD_TASK", expireSecond = 86400)
|
||||
public void execute() {
|
||||
log.info("【房间贡献周奖励】定时任务开始执行...");
|
||||
|
||||
try {
|
||||
// 校验:沙特时间 2025年10月10号之后(包含)才执行
|
||||
int currentDate = ZonedDateTimeAsiaRiyadhUtils.nowDateToInt();
|
||||
if (currentDate < 20251010) {
|
||||
log.info("【房间贡献周奖励】当前日期: {}, 未到活动开始时间(20251010),跳过执行", currentDate);
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. 获取所有房间上周数据
|
||||
List<RoomContributionActivityCount> lastWeekDataList =
|
||||
roomContributionActivityCountService.getAllRoomsLastWeekData();
|
||||
|
||||
if (CollectionUtils.isEmpty(lastWeekDataList)) {
|
||||
log.info("【房间贡献周奖励】没有需要发放的奖励数据");
|
||||
return;
|
||||
}
|
||||
|
||||
log.info("【房间贡献周奖励】待发放奖励房间数: {}", lastWeekDataList.size());
|
||||
|
||||
int successCount = 0;
|
||||
int failCount = 0;
|
||||
|
||||
// 2. 遍历发放奖励
|
||||
for (RoomContributionActivityCount data : lastWeekDataList) {
|
||||
try {
|
||||
// 校验:如果已领取,跳过
|
||||
if (Boolean.TRUE.equals(data.getReceived())) {
|
||||
log.info("【房间贡献周奖励】数据已领取,跳过发放, roomId: {}, recordId: {}",
|
||||
data.getRoomId(), data.getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 计算奖励金币 = 上周贡献金额 × 比例
|
||||
BigDecimal rewardAmount = data.getContributionValue()
|
||||
.multiply(REWARD_RATIO)
|
||||
.setScale(2, RoundingMode.DOWN);
|
||||
|
||||
// 如果奖励金额 <= 0,跳过
|
||||
if (rewardAmount.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
log.warn("【房间贡献周奖励】奖励金额为0,跳过发放, roomId: {}, recordId: {}",
|
||||
data.getRoomId(), data.getId());
|
||||
continue;
|
||||
}
|
||||
|
||||
// 3. 发送金币奖励(需要获取房主ID)
|
||||
// 注意:这里假设从其他地方获取房主ID,你需要根据实际情况调整
|
||||
Long roomOwnerId = getRoomOwnerId(data.getRoomId());
|
||||
if (roomOwnerId == null) {
|
||||
log.warn("【房间贡献周奖励】无法获取房主ID, roomId: {}", data.getRoomId());
|
||||
failCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
walletGoldClient.changeBalance(GoldReceiptCmd.builder()
|
||||
.appIncome()
|
||||
.eventId(data.getRoomId())
|
||||
.userId(roomOwnerId)
|
||||
.origin(GoldOrigin.ROOM_CONTRIBUTION_REWARD)
|
||||
.amount(rewardAmount)
|
||||
.build());
|
||||
|
||||
// 4. 修改数据状态为已领取
|
||||
roomContributionActivityCountService.updateReceivedByRoomId(data.getRoomId(), REWARD_RATIO);
|
||||
|
||||
successCount++;
|
||||
|
||||
log.info("【房间贡献周奖励】发放成功, roomId: {}, roomOwnerId: {}, rewardAmount: {}",
|
||||
data.getRoomId(), roomOwnerId, rewardAmount);
|
||||
|
||||
} catch (Exception e) {
|
||||
failCount++;
|
||||
log.error("【房间贡献周奖励】发放失败, roomId: {}, error: ",
|
||||
data.getRoomId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
log.info("【房间贡献周奖励】定时任务执行完成, 成功: {}, 失败: {}", successCount, failCount);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("【房间贡献周奖励】定时任务执行异常: ", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取房主ID
|
||||
*/
|
||||
private Long getRoomOwnerId(Long roomId) {
|
||||
return roomProfileManagerService.getHomeownerId(roomId);
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,8 @@ package com.red.circle.other.app.dto.clientobject.activity.room;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* 房间奖励信息
|
||||
*
|
||||
@ -14,7 +16,7 @@ public class RoomRewardInfoCO {
|
||||
/**
|
||||
* 倒计时信息
|
||||
*/
|
||||
private CountdownCO countdown;
|
||||
private Timestamp countdown;
|
||||
|
||||
/**
|
||||
* 当前周进度
|
||||
@ -26,32 +28,6 @@ public class RoomRewardInfoCO {
|
||||
*/
|
||||
private LastWeekProgressCO lastWeekProgress;
|
||||
|
||||
/**
|
||||
* 倒计时对象
|
||||
*/
|
||||
@Data
|
||||
public static class CountdownCO {
|
||||
/**
|
||||
* 剩余天数
|
||||
*/
|
||||
private Long days;
|
||||
|
||||
/**
|
||||
* 剩余小时
|
||||
*/
|
||||
private Long hours;
|
||||
|
||||
/**
|
||||
* 剩余分钟
|
||||
*/
|
||||
private Long minutes;
|
||||
|
||||
/**
|
||||
* 剩余秒数
|
||||
*/
|
||||
private Long seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当前周进度
|
||||
*/
|
||||
|
||||
@ -92,13 +92,10 @@ public interface RoomContributionActivityCountService {
|
||||
*/
|
||||
List<RoomContributionActivityCount> listRoomContributionByPH(Long roomId,BigDecimal number);
|
||||
|
||||
/**
|
||||
* 获取房间上周贡献数据(未领取状态)
|
||||
*
|
||||
* @param roomId 房间ID
|
||||
* @return 上周贡献数据
|
||||
*/
|
||||
RoomContributionActivityCount getLastWeekData(Long roomId);
|
||||
/**
|
||||
* 更新奖励金币状态为已发放
|
||||
*/
|
||||
boolean updateRewardCoinsSent(String id);
|
||||
|
||||
/**
|
||||
* 获取所有房间上周贡献数据(未领取状态)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package com.red.circle.other.infra.database.mongo.service.activity.impl;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mongodb.client.result.UpdateResult;
|
||||
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
|
||||
import com.red.circle.component.mongodb.page.MongoPageHelper;
|
||||
import com.red.circle.framework.dto.PageResult;
|
||||
@ -280,19 +281,17 @@ public class RoomContributionActivityCountServiceImpl implements
|
||||
RoomContributionActivityCount.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoomContributionActivityCount getLastWeekData(Long roomId) {
|
||||
// 获取上周的 dateNumber(当前周一 - 7 天)
|
||||
Integer lastWeekDateNumber = ZonedDateTimeAsiaRiyadhUtils.getThisMonday() - 7;
|
||||
|
||||
Criteria criteria = Criteria.where("roomId").is(roomId)
|
||||
.and("dateNumber").is(lastWeekDateNumber)
|
||||
.and("received").is(Boolean.FALSE);
|
||||
|
||||
return mongoTemplate.findOne(Query.query(criteria), RoomContributionActivityCount.class);
|
||||
}
|
||||
@Override
|
||||
public boolean updateRewardCoinsSent(String id) {
|
||||
Query query = new Query(Criteria.where("_id").is(id));
|
||||
Update update = new Update().set("rewardCoinsSent", true);
|
||||
UpdateResult result = mongoTemplate.updateFirst(query, update, RoomContributionActivityCount.class);
|
||||
|
||||
@Override
|
||||
// 检查是否有文档被修改
|
||||
return result.getModifiedCount() > 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RoomContributionActivityCount> getAllRoomsLastWeekData() {
|
||||
// 获取上周的 dateNumber
|
||||
Integer lastWeekDateNumber = ZonedDateTimeAsiaRiyadhUtils.getThisMonday() - 7;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user