diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/redpacket/SendRoomRedPacketCmdExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/redpacket/SendRoomRedPacketCmdExe.java index 0d36f74a..d3a6d47f 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/redpacket/SendRoomRedPacketCmdExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/redpacket/SendRoomRedPacketCmdExe.java @@ -12,7 +12,6 @@ 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.dto.cmd.task.RoomDailyTaskProgressUpdateCmd; -import com.red.circle.other.app.enums.RoomRewardLevelEnum; import com.red.circle.other.app.service.task.RoomDailyTaskProgressService; import com.red.circle.other.app.util.OfficialNoticeUtils; import com.red.circle.other.domain.gateway.RoomRedPacketGateway; @@ -23,15 +22,12 @@ 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.entity.live.RoomProfileManager; 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.enums.task.RoomDailyTaskCode; 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; @@ -42,10 +38,11 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; +import org.springframework.transaction.support.TransactionSynchronization; +import org.springframework.transaction.support.TransactionSynchronizationManager; import java.time.Duration; import java.time.LocalDateTime; -import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -159,26 +156,7 @@ public class SendRoomRedPacketCmdExe { RoomRedPacket redPacket = buildRedPacket(cmd, systemUserId, packetId, expireTime, RoomRedPacketSourceType.PLATFORM); roomRedPacketGateway.save(redPacket); - // 查询上周数据 - deductRoomContribution(cmd.getRoomId(), cmd.getTotalAmount()); - - // 预生成随机金额列表(拼手气红包) - List amounts = generateRandomAmounts(cmd.getTotalAmount(), cmd.getTotalCount()); - long expireSeconds = cmd.getExpireMinutes() * 60; - roomRedPacketCacheService.setRandomAmounts(packetId, amounts, expireSeconds); - - // 写入Redis(红包主数据) - cacheRedPacketData(redPacket); - - // 添加到房间红包列表 - roomRedPacketCacheService.addToRoomList( - cmd.getRoomId(), - packetId, - System.currentTimeMillis() - ); - - // 发送飘窗通知(平台红包) - sendMessage(cmd, packetId); + publishPlatformRedPacket(cmd, redPacket, packetId); log.info("发平台红包成功 packetId={} roomId={} amount={} count={} ", packetId, cmd.getRoomId(), cmd.getTotalAmount(), cmd.getTotalCount()); @@ -186,27 +164,101 @@ 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); + /** + * 执行房间周流水奖励平台红包. + */ + @Transactional(rollbackFor = Exception.class) + public RoomRedPacketCO executeRoomContributionReward(SendRoomRedPacketCmd cmd, + String activityCountId) { + cmd.setPacketType(2); + validateParams(cmd); - 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())); + String packetId = buildRoomContributionRewardPacketId(activityCountId); + boolean locked = roomContributionActivityCountService + .markRewardCoinsSending(activityCountId, packetId); + if (!locked) { + log.warn("房间周流水奖励已被处理 activityCountId={} roomId={}", activityCountId, + cmd.getRoomId()); + return null; + } - boolean updated = roomContributionActivityCountService.updateRewardCoinsSent(lastWeek.getId()); - ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE, updated); + try { + RoomRedPacket redPacket = roomRedPacketGateway.findByPacketId(packetId); + LocalDateTime expireTime = LocalDateTime.now().plusMinutes(cmd.getExpireMinutes()); + if (Objects.isNull(redPacket)) { + Long systemUserId = 0L; + redPacket = buildRedPacket(cmd, systemUserId, packetId, expireTime, + RoomRedPacketSourceType.PLATFORM); + roomRedPacketGateway.save(redPacket); + } else if (isExpired(redPacket)) { + roomRedPacketGateway.resetPlatformPacket(packetId, cmd.getTotalAmount(), + cmd.getTotalCount(), cmd.getExpireMinutes(), expireTime); + redPacket = buildRedPacket(cmd, 0L, packetId, expireTime, + RoomRedPacketSourceType.PLATFORM); + } + + RoomRedPacket finalRedPacket = redPacket; + TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { + @Override + public void afterCommit() { + publishRoomContributionRewardAfterCommit(cmd, finalRedPacket, activityCountId, + packetId); + } + }); + + log.info("房间周流水奖励红包已提交 packetId={} roomId={} activityCountId={} amount={} count={}", + packetId, cmd.getRoomId(), activityCountId, cmd.getTotalAmount(), + cmd.getTotalCount()); + return RoomRedPacketAppConvertor.toCO(redPacket); + } catch (Exception e) { + roomContributionActivityCountService + .resetRewardCoinsSending(activityCountId, packetId, e.getMessage()); + throw e; + } } - /** - * 根据房间ID和日期查询数据 - */ - private RoomContributionActivityCount findByRoomIdAndDateNumber(Long roomId, Integer dateNumber) { - return roomContributionActivityCountService - .findByRoomIdAndDateNumber(roomId, dateNumber) - .orElse(null); + private void publishRoomContributionRewardAfterCommit(SendRoomRedPacketCmd cmd, + RoomRedPacket redPacket, + String activityCountId, + String packetId) { + try { + if (roomRedPacketCacheService.existsRedPacket(packetId)) { + roomRedPacketCacheService.addToRoomList( + cmd.getRoomId(), + packetId, + System.currentTimeMillis() + ); + boolean sent = roomContributionActivityCountService + .markRewardCoinsSent(activityCountId, packetId); + if (!sent) { + log.warn("房间周流水奖励红包已存在但状态标记失败 packetId={} activityCountId={}", + packetId, activityCountId); + } + return; + } + + publishPlatformRedPacket(cmd, redPacket, packetId); + boolean sent = roomContributionActivityCountService + .markRewardCoinsSent(activityCountId, packetId); + if (!sent) { + log.warn("房间周流水奖励红包发布后状态标记失败 packetId={} activityCountId={}", + packetId, activityCountId); + } + } catch (Exception e) { + roomContributionActivityCountService + .resetRewardCoinsSending(activityCountId, packetId, e.getMessage()); + log.error("房间周流水奖励红包发布失败 packetId={} activityCountId={} roomId={}", + packetId, activityCountId, cmd.getRoomId(), e); + } + } + + private String buildRoomContributionRewardPacketId(String activityCountId) { + return "RCWR_" + activityCountId; + } + + private boolean isExpired(RoomRedPacket redPacket) { + return Objects.nonNull(redPacket.getExpireTime()) + && !redPacket.getExpireTime().isAfter(LocalDateTime.now()); } /** @@ -222,9 +274,14 @@ public class SendRoomRedPacketCmdExe { build.put("packetId", packetId); if (cmd.getTotalAmount() >= 30000) { + SysOriginPlatformEnum sysOrigin = SysOriginPlatformEnum + .toEnum(cmd.getReqSysOrigin().getOrigin()); + if (Objects.isNull(sysOrigin)) { + return; + } imGroupClient.sendMessageBroadcast( BroadcastGroupMsgBodyCmd.builder() - .toPlatform(SysOriginPlatformEnum.ATYOU) + .toPlatform(sysOrigin) .type(GroupMessageTypeEnum.ROOM_RED_PACKET) .data(build) .build() @@ -271,6 +328,23 @@ public class SendRoomRedPacketCmdExe { } } + private void publishPlatformRedPacket(SendRoomRedPacketCmd cmd, RoomRedPacket redPacket, + String packetId) { + List amounts = generateRandomAmounts(cmd.getTotalAmount(), cmd.getTotalCount()); + long expireSeconds = cmd.getExpireMinutes() * 60; + roomRedPacketCacheService.setRandomAmounts(packetId, amounts, expireSeconds); + + cacheRedPacketData(redPacket); + + roomRedPacketCacheService.addToRoomList( + cmd.getRoomId(), + packetId, + System.currentTimeMillis() + ); + + sendMessage(cmd, packetId); + } + /** * 扣除用户金币 */ diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/RoomContributionWeeklyRewardTask.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/RoomContributionWeeklyRewardTask.java new file mode 100644 index 00000000..9dc1e25d --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/scheduler/RoomContributionWeeklyRewardTask.java @@ -0,0 +1,202 @@ +package com.red.circle.other.app.scheduler; + +import com.red.circle.common.business.core.enums.SysOriginPlatformEnum; +import com.red.circle.component.redis.annotation.TaskCacheLock; +import com.red.circle.framework.core.dto.ReqSysOrigin; +import com.red.circle.other.app.command.redpacket.SendRoomRedPacketCmdExe; +import com.red.circle.other.app.dto.cmd.SendRoomRedPacketCmd; +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.entity.live.RoomProfileManager; +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 java.math.BigDecimal; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +/** + * 自动发送房间周流水奖励. + */ +@Slf4j +@Component +@RequiredArgsConstructor +@ConditionalOnProperty(name = "scheduler.room-contribution-weekly-reward", havingValue = "true", + matchIfMissing = true) +public class RoomContributionWeeklyRewardTask { + + private static final Integer DEFAULT_EXPIRE_MINUTES = 10; + private static final Integer DEFAULT_TOTAL_COUNT = 10; + private static final BigDecimal DEFAULT_MIN_CONTRIBUTION = BigDecimal.valueOf(100000); + private static final BigDecimal TARAB_MIN_CONTRIBUTION = BigDecimal.valueOf(150000); + + private final SendRoomRedPacketCmdExe sendRoomRedPacketCmdExe; + private final RoomProfileManagerService roomProfileManagerService; + private final RoomContributionActivityCountService roomContributionActivityCountService; + + @Value("${activity.room-contribution.weekly-reward.expire-minutes:10}") + private Integer expireMinutes; + + @Value("${activity.room-contribution.weekly-reward.total-count:10}") + private Integer totalCount; + + @Value("${activity.room-contribution.weekly-reward.repair-enabled:true}") + private Boolean repairEnabled; + + @Value("${activity.room-contribution.weekly-reward.sys-origins:ATYOU}") + private String enabledSysOrigins; + + /** + * 每周一沙特时间 00:08 发送上周房间周流水奖励. + */ + @Scheduled(cron = "0 8 0 ? * MON", zone = "Asia/Riyadh") + @TaskCacheLock(key = "ROOM_CONTRIBUTION_WEEKLY_REWARD_TASK", expireSecond = 600) + public void sendLastWeekRoomContributionRewards() { + sendLastWeekRoomContributionRewards("weekly"); + } + + /** + * 启动后和每分钟补偿上周未发奖励,防止周一任务异常后永久漏发. + */ + @Scheduled( + initialDelayString = "${activity.room-contribution.weekly-reward.repair-initial-delay-ms:60000}", + fixedDelayString = "${activity.room-contribution.weekly-reward.repair-fixed-delay-ms:60000}") + @TaskCacheLock(key = "ROOM_CONTRIBUTION_WEEKLY_REWARD_TASK", expireSecond = 60) + public void repairLastWeekRoomContributionRewards() { + if (!Boolean.TRUE.equals(repairEnabled)) { + return; + } + sendLastWeekRoomContributionRewards("repair"); + } + + private void sendLastWeekRoomContributionRewards(String trigger) { + log.warn("[RoomContributionWeeklyReward] start trigger={}", trigger); + + List list = + roomContributionActivityCountService.listLastWeekRewardUnsentData(); + if (CollectionUtils.isEmpty(list)) { + log.warn("[RoomContributionWeeklyReward] no unsent reward data trigger={}", trigger); + return; + } + + int success = 0; + int fail = 0; + for (RoomContributionActivityCount data : list) { + try { + if (sendReward(data)) { + success++; + } + } catch (Exception e) { + fail++; + log.error("[RoomContributionWeeklyReward] send failed roomId={} dataId={} amount={}", + data.getRoomId(), data.getId(), data.getContributionValue(), e); + } + } + + log.warn("[RoomContributionWeeklyReward] end trigger={} total={} success={} fail={}", + trigger, list.size(), success, fail); + } + + private boolean sendReward(RoomContributionActivityCount data) { + if (Objects.isNull(data) || Objects.isNull(data.getRoomId()) + || Objects.isNull(data.getContributionValue())) { + return false; + } + + RoomProfileManager room = roomProfileManagerService.getById(data.getRoomId()); + SysOriginPlatformEnum sysOrigin = getSysOrigin(room); + if (Objects.isNull(room) || Objects.isNull(sysOrigin)) { + log.warn("[RoomContributionWeeklyReward] skip invalid room roomId={} dataId={}", + data.getRoomId(), data.getId()); + return false; + } + + if (!getEnabledSysOrigins().contains(sysOrigin)) { + log.warn("[RoomContributionWeeklyReward] skip disabled sysOrigin roomId={} dataId={} sysOrigin={}", + data.getRoomId(), data.getId(), sysOrigin); + return false; + } + + if (!meetsPlatformThreshold(sysOrigin, data.getContributionValue())) { + log.warn("[RoomContributionWeeklyReward] skip threshold roomId={} dataId={} sysOrigin={} amount={}", + data.getRoomId(), data.getId(), sysOrigin, data.getContributionValue()); + return false; + } + + RoomRewardLevelEnum level = RoomRewardLevelEnum + .getLevelByAmount(data.getContributionValue().longValue()); + if (Objects.isNull(level)) { + return false; + } + + SendRoomRedPacketCmd cmd = new SendRoomRedPacketCmd(); + cmd.setRoomId(data.getRoomId()); + cmd.setTotalAmount(level.getRewardCoins()); + cmd.setTotalCount(getTotalCount(level.getRewardCoins())); + cmd.setExpireMinutes(getExpireMinutes()); + cmd.setReqUserId(room.getUserId()); + cmd.setReqSysOrigin(ReqSysOrigin.of(sysOrigin.name())); + + if (Objects.isNull(sendRoomRedPacketCmdExe.executeRoomContributionReward(cmd, data.getId()))) { + return false; + } + log.info("[RoomContributionWeeklyReward] sent roomId={} dataId={} level={} rewardCoins={}", + data.getRoomId(), data.getId(), level.getLevel(), level.getRewardCoins()); + return true; + } + + private SysOriginPlatformEnum getSysOrigin(RoomProfileManager room) { + if (Objects.isNull(room) || Objects.isNull(room.getSysOrigin())) { + return null; + } + try { + return SysOriginPlatformEnum.valueOf(room.getSysOrigin()); + } catch (IllegalArgumentException e) { + return null; + } + } + + private boolean meetsPlatformThreshold(SysOriginPlatformEnum sysOrigin, BigDecimal contribution) { + BigDecimal minContribution = Objects.equals(sysOrigin, SysOriginPlatformEnum.TARAB) + ? TARAB_MIN_CONTRIBUTION : DEFAULT_MIN_CONTRIBUTION; + return contribution.compareTo(minContribution) >= 0; + } + + private Set getEnabledSysOrigins() { + if (Objects.isNull(enabledSysOrigins) || enabledSysOrigins.isBlank()) { + return Collections.emptySet(); + } + return Arrays.stream(enabledSysOrigins.split(",")) + .map(String::trim) + .filter(item -> !item.isBlank()) + .map(SysOriginPlatformEnum::toEnum) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + } + + private Integer getExpireMinutes() { + if (Objects.isNull(expireMinutes) || !List.of(1, 3, 5, 10).contains(expireMinutes)) { + return DEFAULT_EXPIRE_MINUTES; + } + return expireMinutes; + } + + private Integer getTotalCount(Long rewardCoins) { + int count = Objects.isNull(totalCount) ? DEFAULT_TOTAL_COUNT : totalCount; + count = Math.max(1, Math.min(count, 100)); + if (Objects.nonNull(rewardCoins)) { + count = Math.min(count, rewardCoins.intValue()); + } + return count; + } +} diff --git a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/gateway/RoomRedPacketGateway.java b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/gateway/RoomRedPacketGateway.java index 7b5b9392..a164ed33 100644 --- a/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/gateway/RoomRedPacketGateway.java +++ b/rc-service/rc-service-other/other-domain/src/main/java/com/red/circle/other/domain/gateway/RoomRedPacketGateway.java @@ -36,6 +36,12 @@ public interface RoomRedPacketGateway { */ void updateRefundStatus(String packetId, Integer refundStatus); + /** + * 重置平台红包发布参数. + */ + void resetPlatformPacket(String packetId, Long totalAmount, Integer totalCount, + Integer expireMinutes, LocalDateTime expireTime); + /** * 查询过期且未退款的红包 */ diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/activity/RoomContributionActivityCount.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/activity/RoomContributionActivityCount.java index 912c1db4..ff4512af 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/activity/RoomContributionActivityCount.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/activity/RoomContributionActivityCount.java @@ -62,6 +62,31 @@ public class RoomContributionActivityCount extends Convert implements Serializab */ Boolean rewardCoinsSent; + /** + * 奖励金币是否发送中. + */ + Boolean rewardCoinsSending; + + /** + * 奖励金币红包ID. + */ + String rewardCoinsPacketId; + + /** + * 奖励金币发送时间. + */ + Timestamp rewardCoinsSentTime; + + /** + * 奖励金币发送中时间. + */ + Timestamp rewardCoinsSendingTime; + + /** + * 奖励金币发送失败原因. + */ + String rewardCoinsSendError; + /** * 比例. */ diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/RoomContributionActivityCountService.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/RoomContributionActivityCountService.java index 815c1a9a..ba97fa68 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/RoomContributionActivityCountService.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/RoomContributionActivityCountService.java @@ -92,11 +92,26 @@ public interface RoomContributionActivityCountService { */ List listRoomContributionByPH(Long roomId,BigDecimal number); - /** - * 更新奖励金币状态为已发放 - */ + /** + * 更新奖励金币状态为已发放 + */ boolean updateRewardCoinsSent(String id); + /** + * 抢占奖励金币发送记录. + */ + boolean markRewardCoinsSending(String id, String packetId); + + /** + * 标记奖励金币已发送. + */ + boolean markRewardCoinsSent(String id, String packetId); + + /** + * 释放奖励金币发送中状态,等待重试. + */ + void resetRewardCoinsSending(String id, String packetId, String reason); + /** * 获取所有房间上周贡献数据(未领取状态) * @@ -104,6 +119,13 @@ public interface RoomContributionActivityCountService { */ List getAllRoomsLastWeekData(); + /** + * 获取所有房间上周贡献数据(平台奖励未发放状态) + * + * @return 所有房间上周贡献数据列表 + */ + List listLastWeekRewardUnsentData(); + /** * 根据房间ID和日期查询数据 * diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/impl/RoomContributionActivityCountServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/impl/RoomContributionActivityCountServiceImpl.java index fb480617..78ade878 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/impl/RoomContributionActivityCountServiceImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/service/activity/impl/RoomContributionActivityCountServiceImpl.java @@ -14,6 +14,7 @@ import com.red.circle.tool.core.date.ZonedDateTimeAsiaRiyadhUtils; import com.red.circle.tool.core.text.StringUtils; import java.math.BigDecimal; import java.math.RoundingMode; +import java.time.format.DateTimeFormatter; import java.util.Comparator; import java.util.List; import java.util.Objects; @@ -45,6 +46,7 @@ public class RoomContributionActivityCountServiceImpl implements private final MongoPageHelper mongoPageHelper; private static final BigDecimal integralMin = BigDecimal.valueOf(100000); private static final BigDecimal otherIntegralMin = BigDecimal.valueOf(150000); + private static final long REWARD_SENDING_EXPIRE_MILLIS = 2 * 60 * 1000L; private Criteria getUniquenessCriteria(Long roomId, Integer dateNumber) { return Criteria.where("id").is(getUniqueId(roomId, dateNumber)); @@ -291,10 +293,53 @@ public class RoomContributionActivityCountServiceImpl implements return result.getModifiedCount() > 0; } + @Override + public boolean markRewardCoinsSending(String id, String packetId) { + Query query = Query.query(new Criteria().andOperator( + Criteria.where("_id").is(id), + unsentRewardCriteria(), + rewardNotSendingOrExpiredCriteria() + )); + Update update = new Update() + .set("rewardCoinsSending", Boolean.TRUE) + .set("rewardCoinsPacketId", packetId) + .set("rewardCoinsSendingTime", TimestampUtils.now()) + .unset("rewardCoinsSendError"); + UpdateResult result = mongoTemplate.updateFirst(query, update, + RoomContributionActivityCount.class); + return result.getModifiedCount() > 0; + } + + @Override + public boolean markRewardCoinsSent(String id, String packetId) { + Query query = Query.query(Criteria.where("_id").is(id) + .and("rewardCoinsPacketId").is(packetId)); + Update update = new Update() + .set("rewardCoinsSent", Boolean.TRUE) + .set("rewardCoinsSending", Boolean.FALSE) + .set("rewardCoinsSentTime", TimestampUtils.now()) + .unset("rewardCoinsSendError"); + UpdateResult result = mongoTemplate.updateFirst(query, update, + RoomContributionActivityCount.class); + return result.getModifiedCount() > 0; + } + + @Override + public void resetRewardCoinsSending(String id, String packetId, String reason) { + Query query = Query.query(new Criteria().andOperator( + Criteria.where("_id").is(id), + Criteria.where("rewardCoinsPacketId").is(packetId), + unsentRewardCriteria() + )); + Update update = new Update() + .set("rewardCoinsSending", Boolean.FALSE) + .set("rewardCoinsSendError", limitErrorReason(reason)); + mongoTemplate.updateFirst(query, update, RoomContributionActivityCount.class); + } + @Override public List getAllRoomsLastWeekData() { - // 获取上周的 dateNumber - Integer lastWeekDateNumber = ZonedDateTimeAsiaRiyadhUtils.getThisMonday() - 7; + Integer lastWeekDateNumber = getLastWeekDateNumber(); Criteria criteria = Criteria.where("dateNumber").is(lastWeekDateNumber) .and("received").is(Boolean.FALSE); @@ -302,6 +347,18 @@ public class RoomContributionActivityCountServiceImpl implements return mongoTemplate.find(Query.query(criteria), RoomContributionActivityCount.class); } + @Override + public List listLastWeekRewardUnsentData() { + Criteria criteria = new Criteria().andOperator( + Criteria.where("dateNumber").is(getLastWeekDateNumber()), + Criteria.where("contributionValue").gte(integralMin), + unsentRewardCriteria(), + rewardNotSendingOrExpiredCriteria() + ); + + return mongoTemplate.find(Query.query(criteria), RoomContributionActivityCount.class); + } + @Override public Optional findByRoomIdAndDateNumber(Long roomId, Integer dateNumber) { Criteria criteria = Criteria.where("roomId").is(roomId) @@ -315,4 +372,32 @@ public class RoomContributionActivityCountServiceImpl implements return Optional.ofNullable(result); } + private Integer getLastWeekDateNumber() { + return Integer.valueOf(ZonedDateTimeAsiaRiyadhUtils.getLastWeekMonday() + .format(DateTimeFormatter.ofPattern("yyyyMMdd"))); + } + + private Criteria unsentRewardCriteria() { + return new Criteria().orOperator( + Criteria.where("rewardCoinsSent").exists(false), + Criteria.where("rewardCoinsSent").ne(Boolean.TRUE) + ); + } + + private Criteria rewardNotSendingOrExpiredCriteria() { + return new Criteria().orOperator( + Criteria.where("rewardCoinsSending").exists(false), + Criteria.where("rewardCoinsSending").ne(Boolean.TRUE), + Criteria.where("rewardCoinsSendingTime") + .lt(new java.sql.Timestamp(System.currentTimeMillis() - REWARD_SENDING_EXPIRE_MILLIS)) + ); + } + + private String limitErrorReason(String reason) { + if (StringUtils.isBlank(reason) || reason.length() <= 500) { + return reason; + } + return reason.substring(0, 500); + } + } diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/redpacket/RoomRedPacketDAO.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/redpacket/RoomRedPacketDAO.java index 62402a8f..8d769088 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/redpacket/RoomRedPacketDAO.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/dao/redpacket/RoomRedPacketDAO.java @@ -36,6 +36,15 @@ public interface RoomRedPacketDAO { */ int updateRefundStatus(@Param("packetId") String packetId, @Param("refundStatus") Integer refundStatus); + /** + * 重置平台红包发布参数 + */ + int resetPlatformPacket(@Param("packetId") String packetId, + @Param("totalAmount") Long totalAmount, + @Param("totalCount") Integer totalCount, + @Param("expireMinutes") Integer expireMinutes, + @Param("expireTime") LocalDateTime expireTime); + /** * 查询过期且未退款的红包 */ diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RoomRedPacketGatewayImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RoomRedPacketGatewayImpl.java index 717524b0..a6e8636b 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RoomRedPacketGatewayImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/gateway/RoomRedPacketGatewayImpl.java @@ -53,6 +53,13 @@ public class RoomRedPacketGatewayImpl implements RoomRedPacketGateway { roomRedPacketDAO.updateRefundStatus(packetId, refundStatus); } + @Override + public void resetPlatformPacket(String packetId, Long totalAmount, Integer totalCount, + Integer expireMinutes, LocalDateTime expireTime) { + roomRedPacketDAO.resetPlatformPacket(packetId, totalAmount, totalCount, expireMinutes, + expireTime); + } + @Override public List findExpiredAndNotRefunded(LocalDateTime now) { List entities = roomRedPacketDAO.selectExpiredAndNotRefunded(now); diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/resources/dao/redpacket/RoomRedPacketDAO.xml b/rc-service/rc-service-other/other-infrastructure/src/main/resources/dao/redpacket/RoomRedPacketDAO.xml index ba08c484..24ed3ffc 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/resources/dao/redpacket/RoomRedPacketDAO.xml +++ b/rc-service/rc-service-other/other-infrastructure/src/main/resources/dao/redpacket/RoomRedPacketDAO.xml @@ -75,6 +75,21 @@ WHERE packet_id = #{packetId} + + UPDATE room_red_packet + SET total_amount = #{totalAmount}, + total_count = #{totalCount}, + remain_amount = #{totalAmount}, + remain_count = #{totalCount}, + expire_minutes = #{expireMinutes}, + expire_time = #{expireTime}, + status = 1, + refund_status = 0, + update_time = NOW() + WHERE packet_id = #{packetId} + AND source_type = 2 + +