This commit is contained in:
hy001 2026-05-21 15:43:38 +08:00
parent c02050274b
commit 3f59e5b653
21 changed files with 448 additions and 167 deletions

View File

@ -46,9 +46,14 @@ public class GiveGiftConfig implements Serializable {
*/
private String type;
/**
* 礼物tab.
*/
private String giftTab;
}
/**
* 礼物tab.
*/
private String giftTab;
/**
* CP礼物关系类型CP/BROTHER/SISTERS.
*/
private String cpRelationType;
}

View File

@ -91,15 +91,20 @@ public class GiftConfigDTO implements Serializable {
*/
private String type;
/**
* 礼物tab.
*/
private String giftTab;
/**
* 0.未删除 1.已删除.
*/
private Boolean del;
/**
* 礼物tab.
*/
private String giftTab;
/**
* CP礼物关系类型CP/BROTHER/SISTERS.
*/
private String cpRelationType;
/**
* 0.未删除 1.已删除.
*/
private Boolean del;
/**
* 幸运礼物规格ID.

View File

@ -86,15 +86,20 @@ public class SysGiftConfigCO implements Serializable {
*/
private String type;
/**
* 礼物tab.
*/
private String giftTab;
/**
* 0.未删除 1.已删除.
*/
private Boolean del;
/**
* 礼物tab.
*/
private String giftTab;
/**
* CP礼物关系类型CP/BROTHER/SISTERS.
*/
private String cpRelationType;
/**
* 0.未删除 1.已删除.
*/
private Boolean del;
/**
* 幸运礼物规格ID.

View File

@ -37,9 +37,12 @@ import org.springframework.stereotype.Component;
@Slf4j
@Component
@RequiredArgsConstructor
public class ProcessCpApplyCmd {
private final CpApplyService cpApplyService;
public class ProcessCpApplyCmd {
private static final int CP_MAX_COUNT = 1;
private static final int FRIEND_MAX_COUNT = 3;
private final CpApplyService cpApplyService;
private final CpValueService cpValueService;
private final ImMessageClient imMessageClient;
private final WalletGoldClient walletGoldClient;
@ -73,12 +76,12 @@ public class ProcessCpApplyCmd {
cpRelationshipService.existsCp(cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId(),
relationType));
// 检查CP数量限制最多4个
int senderCpCount = cpRelationshipService.countCp(cpApply.getSendApplyUserId());
int receiverCpCount = cpRelationshipService.countCp(cpApply.getAcceptApplyUserId());
ResponseAssert.isFalse(UserRelationErrorCode.CP_LIMIT_EXCEEDED, senderCpCount >= 4);
ResponseAssert.isFalse(UserRelationErrorCode.CP_LIMIT_EXCEEDED, receiverCpCount >= 4);
}
int maxCount = relationMaxCount(relationType);
ResponseAssert.isFalse(UserRelationErrorCode.CP_LIMIT_EXCEEDED,
cpRelationshipService.countCp(cpApply.getSendApplyUserId(), relationType) >= maxCount);
ResponseAssert.isFalse(UserRelationErrorCode.CP_LIMIT_EXCEEDED,
cpRelationshipService.countCp(cpApply.getAcceptApplyUserId(), relationType) >= maxCount);
}
// 操作失败
ResponseAssert.isTrue(CommonErrorCode.OPERATING_FAILURE,
@ -89,8 +92,6 @@ public class ProcessCpApplyCmd {
return;
}
refuseStatusWait(cmd, cpApply, relationType);
if (isReconcile) {
// 复合更新状态为NORMAL
cpRelationshipService.reconcile(cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId(),
@ -100,19 +101,32 @@ public class ProcessCpApplyCmd {
cpRelationshipService
.addCp(cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId(), createCpValue(),
cmd.requireReqSysOrigin(), relationType);
}
cpRelationshipCacheService.remove(Arrays.asList(cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId()));
}
private void refuseStatusWait(ProcessApplyCmd cmd, CpApply cpApply, String relationType) {
}
refuseStatusWaitIfLimitReached(cmd, cpApply, relationType);
cpRelationshipCacheService.remove(Arrays.asList(cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId()));
}
private void refuseStatusWaitIfLimitReached(ProcessApplyCmd cmd, CpApply cpApply,
String relationType) {
if (cpRelationshipService.countCp(cpApply.getAcceptApplyUserId(), relationType)
< relationMaxCount(relationType)) {
return;
}
cpApplyService.refuseStatusWait(cmd.requiredReqUserId(), relationType);
userMqMessageService.cpApplyDelayed(
new CpApplyEvent()
userMqMessageService.cpApplyDelayed(
new CpApplyEvent()
.setId(cpApply.getId())
.setSysOrigin(SysOriginPlatformEnum.valueOf(cmd.requireReqSysOrigin())),
TimestampUtils.nowPlusMinutes(1));
}
TimestampUtils.nowPlusMinutes(1));
}
private int relationMaxCount(String relationType) {
return Objects.equals(CpRelationshipType.CP, CpRelationshipType.of(relationType))
? CP_MAX_COUNT
: FRIEND_MAX_COUNT;
}
private void returnGoldCoins(ProcessApplyCmd cmd, CpApply cpApply) {
if (Objects.isNull(cpApply.getApplyConsumeGold())

View File

@ -46,8 +46,11 @@ import org.springframework.stereotype.Component;
@RequiredArgsConstructor
@Slf4j
public class SendCpApplyCmdExe {
private final CpApplyService cpApplyService;
private static final int CP_MAX_COUNT = 1;
private static final int FRIEND_MAX_COUNT = 3;
private final CpApplyService cpApplyService;
private final OfficialNoticeClient officialNoticeClient;
private final WalletGoldClient walletGoldClient;
private final UserMqMessageService userMqMessageService;
@ -63,12 +66,18 @@ public class SendCpApplyCmdExe {
}
public boolean autoCreateFromCpGift(Long sendUserId, Long acceptUserId, String sysOrigin) {
return autoCreateFromCpGift(sendUserId, acceptUserId, sysOrigin, CpRelationshipType.CP.name());
}
public boolean autoCreateFromCpGift(Long sendUserId, Long acceptUserId, String sysOrigin,
String relationTypeValue) {
try {
process(sendUserId, acceptUserId, sysOrigin, CpRelationshipType.CP.name(), false);
process(sendUserId, acceptUserId, sysOrigin, relationTypeValue, false);
return true;
} catch (Exception ex) {
log.info("[CP] skip auto create cp apply from gift, sendUserId={}, acceptUserId={}, reason={}",
sendUserId, acceptUserId, ex.getMessage());
log.info(
"[CP] skip auto create cp apply from gift, sendUserId={}, acceptUserId={}, relationType={}, reason={}",
sendUserId, acceptUserId, relationTypeValue, ex.getMessage());
return false;
}
}
@ -101,16 +110,12 @@ public class SendCpApplyCmdExe {
cpRelationshipService
.existsCp(sendUserId, acceptUserId, relationType.name()));
// 检查CP数量限制最多4个
int senderCpCount = cpRelationshipService.countCp(sendUserId);
int receiverCpCount = cpRelationshipService.countCp(acceptUserId);
ResponseAssert.isFalse(UserRelationErrorCode.CP_LIMIT_EXCEEDED, senderCpCount >= 4);
ResponseAssert.isFalse(UserRelationErrorCode.CP_LIMIT_EXCEEDED, receiverCpCount >= 4);
validateRelationLimit(sendUserId, acceptUserId, relationType);
}
// 您已发送申请
ResponseAssert.isFalse(UserRelationErrorCode.YOU_HAVE_SENT_AN_APPLICATION,
cpApplyService.existsNotProcessSendApply(sendUserId, relationType.name()));
cpApplyService.exists(acceptUserId, sendUserId, relationType.name()));
// 对方已向你发送申请
ResponseAssert.isFalse(UserRelationErrorCode.OTHER_SIDE_ALREADY_APPLIED,
@ -166,6 +171,19 @@ public class SendCpApplyCmdExe {
TimestampUtils.nowPlusDays(1));
}
private void validateRelationLimit(Long sendUserId, Long acceptUserId,
CpRelationshipType relationType) {
int maxCount = relationMaxCount(relationType);
ResponseAssert.isFalse(UserRelationErrorCode.CP_LIMIT_EXCEEDED,
cpRelationshipService.countCp(sendUserId, relationType.name()) >= maxCount);
ResponseAssert.isFalse(UserRelationErrorCode.CP_LIMIT_EXCEEDED,
cpRelationshipService.countCp(acceptUserId, relationType.name()) >= maxCount);
}
private int relationMaxCount(CpRelationshipType relationType) {
return Objects.equals(relationType, CpRelationshipType.CP) ? CP_MAX_COUNT : FRIEND_MAX_COUNT;
}
private CpRelationshipType parseRelationType(String relationTypeValue) {
try {
return CpRelationshipType.of(relationTypeValue);
@ -177,12 +195,10 @@ public class SendCpApplyCmdExe {
private void validateRelationTypeGender(CpRelationshipType relationType, UserProfileDTO userProfile,
UserProfileDTO acceptUserProfile) {
if (Objects.equals(relationType, CpRelationshipType.CP)) {
ResponseAssert.isFalse(UserRelationErrorCode.UNAVAILABLE_SAME_GENDER,
Objects.equals(userProfile.getUserSex(), acceptUserProfile.getUserSex()));
if (!Objects.equals(relationType, CpRelationshipType.CP)) {
return;
}
ResponseAssert.isTrue(UserRelationErrorCode.RELATION_TYPE_GENDER_NOT_MATCH,
ResponseAssert.isTrue(UserRelationErrorCode.UNAVAILABLE_SAME_GENDER,
relationType.genderMatched(userProfile.getUserSex(), acceptUserProfile.getUserSex()));
}

View File

@ -81,11 +81,12 @@ public interface GiftAppConvertor {
return new GiveGiftConfig()
.setId(giftConfig.getId())
.setGiftCandy(giftConfig.getGiftCandy())
.setGiftIntegral(giftConfig.getGiftIntegral())
.setSpecial(giftConfig.getSpecial())
.setType(giftConfig.getType())
.setGiftTab(giftConfig.getGiftTab());
}
.setGiftIntegral(giftConfig.getGiftIntegral())
.setSpecial(giftConfig.getSpecial())
.setType(giftConfig.getType())
.setGiftTab(giftConfig.getGiftTab())
.setCpRelationType(giftConfig.getCpRelationType());
}
default GiveAwayGiftBatchEvent toBackpackGift(GiveAwayGiftBackpackCmd cmd,
GiftConfigDTO giftConfig, Long trackId) {

View File

@ -807,12 +807,13 @@ public class GiveGiftsListener implements MessageListener {
GiveGiftConfig giftConfig = event.getGiftConfig();
return new GiftValue()
.setCurrencyType(giftConfig.getType())
.setGiftType(getGiftType(event, giftConfig))
.setUnitPrice(giftConfig.getGiftCandy())
.setQuantity(event.getQuantity())
.setUserSize(event.acceptUserSize())
return new GiftValue()
.setCurrencyType(giftConfig.getType())
.setGiftType(getGiftType(event, giftConfig))
.setCpRelationType(giftConfig.getCpRelationType())
.setUnitPrice(giftConfig.getGiftCandy())
.setQuantity(event.getQuantity())
.setUserSize(event.acceptUserSize())
.setActualAmount(event.countConsumAmountTotal())
.setGiftValue(event.checkGiftTypeEqGold() ?
event.countSingleGiftGolds()

View File

@ -57,9 +57,9 @@ import com.red.circle.other.infra.database.rds.entity.live.RoomMember;
import com.red.circle.other.infra.database.rds.entity.user.user.ConfessionChance;
import com.red.circle.other.infra.database.rds.entity.user.user.CpBlessRecord;
import com.red.circle.other.infra.database.rds.entity.user.user.CpRelationship;
import com.red.circle.other.infra.database.rds.entity.user.user.CpValue;
import com.red.circle.other.infra.database.rds.entity.user.user.FriendshipCard;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicContentService;
import com.red.circle.other.infra.database.rds.entity.user.user.CpValue;
import com.red.circle.other.infra.database.rds.entity.user.user.FriendshipCard;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicContentService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicGiftService;
import com.red.circle.other.infra.database.rds.service.dynamic.DynamicMessageService;
import com.red.circle.other.infra.database.rds.service.game.GameRoomPkIntegralRecordService;
@ -70,9 +70,10 @@ import com.red.circle.other.infra.database.rds.service.user.user.ConfessionChanc
import com.red.circle.other.infra.database.rds.service.user.user.ConsumptionLevelService;
import com.red.circle.other.infra.database.rds.service.user.user.CpBlessRecordService;
import com.red.circle.other.infra.database.rds.service.user.user.CpRelationshipService;
import com.red.circle.other.infra.database.rds.service.user.user.CpValueService;
import com.red.circle.other.infra.database.rds.service.user.user.FriendshipCardService;
import com.red.circle.other.inner.enums.config.EnumConfigKey;
import com.red.circle.other.infra.database.rds.service.user.user.CpValueService;
import com.red.circle.other.infra.database.rds.service.user.user.FriendshipCardService;
import com.red.circle.other.infra.enums.user.user.CpRelationshipType;
import com.red.circle.other.inner.enums.config.EnumConfigKey;
import com.red.circle.other.inner.enums.game.GamePkTypeEnum;
import com.red.circle.other.inner.enums.material.GiftCurrencyType;
import com.red.circle.other.inner.enums.material.GiftSpecialEnum;
@ -378,12 +379,15 @@ public class GiftCountStrategy implements GiftStrategy {
if (CollectionUtils.isEmpty(runningWater.getAcceptUsers())) {
return;
}
String relationType = CpRelationshipType.normalize(
runningWater.getGiftValue().getCpRelationType());
runningWater.getAcceptUsers().forEach(accept -> {
if (Objects.equals(runningWater.getUserId(), accept.getAcceptUserId())) {
return;
}
sendCpApplyCmdExe.autoCreateFromCpGift(
runningWater.getUserId(), accept.getAcceptUserId(), runningWater.getSysOrigin());
runningWater.getUserId(), accept.getAcceptUserId(), runningWater.getSysOrigin(),
relationType);
});
} catch (Exception ex) {
log.warn("[CP] skip auto create cp apply from gift, runningWaterId={}, giftId={}, sendUserId={}, reason={}",

View File

@ -0,0 +1,110 @@
package com.red.circle.other.app.command.user;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.red.circle.external.inner.endpoint.message.OfficialNoticeClient;
import com.red.circle.external.inner.model.cmd.message.notice.official.NoticeExtTemplateTypeCmd;
import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.mq.rocket.business.producer.UserMqMessageService;
import com.red.circle.other.app.convertor.user.UserProfileAppConvertor;
import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.gateway.user.ability.UserRegionGateway;
import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.rds.entity.user.user.CpApply;
import com.red.circle.other.infra.database.rds.service.user.user.CpApplyService;
import com.red.circle.other.infra.database.rds.service.user.user.CpRelationshipService;
import com.red.circle.other.inner.model.dto.user.UserProfileDTO;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
class SendCpApplyCmdExeTest {
@Test
void autoCreateFromCpGiftShouldNotRestrictBrotherAndSistersGender() {
Fixture fixture = new Fixture(1, 0);
assertTrue(fixture.exe.autoCreateFromCpGift(1001L, 2001L, "LIKEI", "BROTHER"));
assertEquals("BROTHER", fixture.savedApply().getRelationType());
fixture = new Fixture(0, 1);
assertTrue(fixture.exe.autoCreateFromCpGift(1001L, 2001L, "LIKEI", "SISTERS"));
assertEquals("SISTERS", fixture.savedApply().getRelationType());
}
@Test
void autoCreateFromCpGiftShouldSkipSameGenderCp() {
Fixture fixture = new Fixture(1, 1);
assertFalse(fixture.exe.autoCreateFromCpGift(1001L, 2001L, "LIKEI", "CP"));
verify(fixture.cpApplyService, never()).save(any(CpApply.class));
}
private static class Fixture {
private final CpApplyService cpApplyService = mock(CpApplyService.class);
private final SendCpApplyCmdExe exe;
private Fixture(Integer sendSex, Integer acceptSex) {
OfficialNoticeClient officialNoticeClient = mock(OfficialNoticeClient.class);
WalletGoldClient walletGoldClient = mock(WalletGoldClient.class);
UserMqMessageService userMqMessageService = mock(UserMqMessageService.class);
CpRelationshipService cpRelationshipService = mock(CpRelationshipService.class);
EnumConfigCacheService enumConfigCacheService = mock(EnumConfigCacheService.class);
UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
UserProfileAppConvertor userProfileAppConvertor = mock(UserProfileAppConvertor.class);
UserRegionGateway userRegionGateway = mock(UserRegionGateway.class);
UserProfile sendProfile = new UserProfile();
UserProfile acceptProfile = new UserProfile();
UserProfileDTO sendProfileDTO = profile(1001L, sendSex);
UserProfileDTO acceptProfileDTO = profile(2001L, acceptSex);
when(userRegionGateway.checkEqRegion(1001L, 2001L)).thenReturn(true);
when(userProfileGateway.getByUserId(1001L)).thenReturn(sendProfile);
when(userProfileGateway.getByUserId(2001L)).thenReturn(acceptProfile);
when(userProfileAppConvertor.toUserProfileDTO(sendProfile)).thenReturn(sendProfileDTO);
when(userProfileAppConvertor.toUserProfileDTO(acceptProfile)).thenReturn(acceptProfileDTO);
when(officialNoticeClient.send(any(NoticeExtTemplateTypeCmd.class)))
.thenReturn(ResultResponse.success());
exe = new SendCpApplyCmdExe(
cpApplyService,
officialNoticeClient,
walletGoldClient,
userMqMessageService,
cpRelationshipService,
enumConfigCacheService,
userProfileGateway,
userProfileAppConvertor,
userRegionGateway
);
}
private CpApply savedApply() {
ArgumentCaptor<CpApply> captor = ArgumentCaptor.forClass(CpApply.class);
verify(cpApplyService).save(captor.capture());
return captor.getValue();
}
private static UserProfileDTO profile(Long userId, Integer sex) {
UserProfileDTO userProfile = new UserProfileDTO();
userProfile.setId(userId);
userProfile.setUserSex(sex);
userProfile.setAccount(userId.toString());
userProfile.setUserNickname("user-" + userId);
userProfile.setCountryCode("SA");
userProfile.setCountryName("Saudi Arabia");
return userProfile;
}
}
}

View File

@ -63,15 +63,20 @@ public class GiftConfigCO extends ClientObject {
*/
private String type;
/**
* 礼物tab.
*/
private String giftTab;
/**
* 规格ID.
*/
@JsonSerialize(using = ToStringSerializer.class)
/**
* 礼物tab.
*/
private String giftTab;
/**
* CP礼物关系类型CP/BROTHER/SISTERS.
*/
private String cpRelationType;
/**
* 规格ID.
*/
@JsonSerialize(using = ToStringSerializer.class)
private Long standardId;
/**

View File

@ -27,15 +27,20 @@ public class GiftValue implements Serializable {
*/
private String currencyType;
/**
* 礼物类型.
*/
private String giftType;
/**
* 礼物单价.
*/
private BigDecimal unitPrice;
/**
* 礼物类型.
*/
private String giftType;
/**
* CP礼物关系类型CP/BROTHER/SISTERS.
*/
private String cpRelationType;
/**
* 礼物单价.
*/
private BigDecimal unitPrice;
/**
* 发送礼物数量.

View File

@ -106,17 +106,23 @@ public class GiftConfig extends TimestampBaseEntity implements Serializable {
@TableField("type")
private String type;
/**
* 礼物tab.
*/
@TableField("gift_tab")
private String giftTab;
/**
* 0.未删除 1.已删除.
*/
@TableField("is_del")
private Boolean del;
/**
* 礼物tab.
*/
@TableField("gift_tab")
private String giftTab;
/**
* CP礼物关系类型CP/BROTHER/SISTERS.
*/
@TableField("cp_relation_type")
private String cpRelationType;
/**
* 0.未删除 1.已删除.
*/
@TableField("is_del")
private Boolean del;
/**
* 幸运礼物规格ID.

View File

@ -5,12 +5,13 @@ import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.framework.dto.PageResult;
import com.red.circle.framework.mybatis.constant.PageConstant;
import com.red.circle.framework.mybatis.service.impl.BaseServiceImpl;
import com.red.circle.other.infra.database.rds.dao.gift.GiftConfigDAO;
import com.red.circle.other.infra.database.rds.entity.gift.GiftConfig;
import com.red.circle.other.infra.database.rds.service.gift.GiftConfigService;
import com.red.circle.other.inner.enums.material.GiftCurrencyType;
import com.red.circle.other.inner.enums.material.GiftSpecialEnum;
import com.red.circle.other.inner.enums.material.GiftTabEnum;
import com.red.circle.other.infra.database.rds.dao.gift.GiftConfigDAO;
import com.red.circle.other.infra.database.rds.entity.gift.GiftConfig;
import com.red.circle.other.infra.database.rds.service.gift.GiftConfigService;
import com.red.circle.other.infra.enums.user.user.CpRelationshipType;
import com.red.circle.other.inner.enums.material.GiftCurrencyType;
import com.red.circle.other.inner.enums.material.GiftSpecialEnum;
import com.red.circle.other.inner.enums.material.GiftTabEnum;
import com.red.circle.other.inner.model.cmd.sys.GiftQryCmd;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.num.NumUtils;
@ -223,20 +224,29 @@ public class GiftConfigServiceImpl extends BaseServiceImpl<GiftConfigDAO, GiftCo
.set(GiftConfig::getSpecial, giftConfig.getSpecial())
.set(GiftConfig::getRegions, giftConfig.getRegions())
.set(GiftConfig::getType, giftConfig.getType())
.set(GiftConfig::getSort, giftConfig.getSort())
.set(GiftConfig::getGiftTab, giftConfig.getGiftTab())
.set(GiftConfig::getStandardId, giftConfig.getStandardId())
.set(GiftConfig::getExpiredTime, giftConfig.getExpiredTime())
.set(GiftConfig::getExplanationGift,
.set(GiftConfig::getSort, giftConfig.getSort())
.set(GiftConfig::getGiftTab, giftConfig.getGiftTab())
.set(GiftConfig::getCpRelationType, normalizeCpRelationType(giftConfig))
.set(GiftConfig::getStandardId, giftConfig.getStandardId())
.set(GiftConfig::getExpiredTime, giftConfig.getExpiredTime())
.set(GiftConfig::getExplanationGift,
Objects.nonNull(giftConfig.getExplanationGift()) ? giftConfig.getExplanationGift()
: Boolean.FALSE)
.set(GiftConfig::getUserId, giftConfig.getUserId())
.eq(GiftConfig::getId, giftConfig.getId())
.last(PageConstant.LIMIT_ONE)
.execute();
}
@Override
.execute();
}
private String normalizeCpRelationType(GiftConfig giftConfig) {
if (Objects.isNull(giftConfig)
|| !Objects.equals(giftConfig.getGiftTab(), GiftTabEnum.CP.name())) {
return null;
}
return CpRelationshipType.normalize(giftConfig.getCpRelationType());
}
@Override
public Boolean switchDelStatus(Long id, Boolean status) {
return update().set(GiftConfig::getDel, status)
.eq(GiftConfig::getId, id)

View File

@ -123,16 +123,21 @@ public interface CpRelationshipService extends BaseService<CpRelationship> {
*/
CpRelationship getByUserIdOrCpUserId(Long userId, String relationType);
/**
* 获取用户正常CP数量.
*
* @param userId 用户id
* @return CP数量
*/
int countCp(Long userId);
/**
* 获取分手中的CP关系.
/**
* 获取用户正常CP数量.
*
* @param userId 用户id
* @return CP数量
*/
int countCp(Long userId);
/**
* 获取用户指定类型正常关系数量.
*/
int countCp(Long userId, String relationType);
/**
* 获取分手中的CP关系.
*
* @param userId 用户id
* @param cpUserId cp用户id

View File

@ -201,13 +201,23 @@ public class CpRelationshipServiceImpl extends
return cpUser;
}
@Override
public int countCp(Long userId) {
return Math.toIntExact(query()
.eq(CpRelationship::getUserId, userId)
.count());
}
@Override
public int countCp(Long userId) {
return Math.toIntExact(query()
.eq(CpRelationship::getUserId, userId)
.eq(CpRelationship::getStatus, CpRelationshipStatus.NORMAL.name())
.count());
}
@Override
public int countCp(Long userId, String relationType) {
return Math.toIntExact(query()
.eq(CpRelationship::getUserId, userId)
.eq(CpRelationship::getStatus, CpRelationshipStatus.NORMAL.name())
.eq(CpRelationship::getRelationType, CpRelationshipType.normalize(relationType))
.count());
}
@Override
public CpRelationship getDismissingCp(Long userId, Long cpUserId) {
return getDismissingCp(userId, cpUserId, CpRelationshipType.CP.name());

View File

@ -15,18 +15,15 @@ public enum CpRelationshipType {
CP,
/**
* Brothers, requires both users to be male.
* Brothers.
*/
BROTHER,
/**
* Sisters, requires both users to be female.
* Sisters.
*/
SISTERS;
private static final int FEMALE = 0;
private static final int MALE = 1;
public static CpRelationshipType of(String value) {
if (StringUtils.isBlank(value)) {
return CP;
@ -48,8 +45,7 @@ public enum CpRelationshipType {
public boolean genderMatched(Integer sendUserSex, Integer acceptUserSex) {
return switch (this) {
case CP -> !Objects.equals(sendUserSex, acceptUserSex);
case BROTHER -> Objects.equals(sendUserSex, MALE) && Objects.equals(acceptUserSex, MALE);
case SISTERS -> Objects.equals(sendUserSex, FEMALE) && Objects.equals(acceptUserSex, FEMALE);
case BROTHER, SISTERS -> true;
};
}

View File

@ -0,0 +1,30 @@
package com.red.circle.other.infra.enums.user.user;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
class CpRelationshipTypeTest {
@Test
void cpRequiresDifferentGender() {
assertTrue(CpRelationshipType.CP.genderMatched(1, 0));
assertTrue(CpRelationshipType.CP.genderMatched(0, 1));
assertFalse(CpRelationshipType.CP.genderMatched(1, 1));
assertFalse(CpRelationshipType.CP.genderMatched(0, 0));
}
@Test
void brotherAndSistersDoNotRestrictGender() {
assertTrue(CpRelationshipType.BROTHER.genderMatched(1, 1));
assertTrue(CpRelationshipType.BROTHER.genderMatched(1, 0));
assertTrue(CpRelationshipType.BROTHER.genderMatched(0, 1));
assertTrue(CpRelationshipType.BROTHER.genderMatched(0, 0));
assertTrue(CpRelationshipType.SISTERS.genderMatched(1, 1));
assertTrue(CpRelationshipType.SISTERS.genderMatched(1, 0));
assertTrue(CpRelationshipType.SISTERS.genderMatched(0, 1));
assertTrue(CpRelationshipType.SISTERS.genderMatched(0, 0));
}
}

View File

@ -6,10 +6,12 @@ import com.red.circle.other.app.inner.convertor.material.GiftInnerConvertor;
import com.red.circle.other.app.inner.service.material.gift.GiftConfigClientService;
import com.red.circle.other.infra.database.cache.service.other.GameLuckyGiftCacheService;
import com.red.circle.other.infra.database.cache.service.other.GiftCacheService;
import com.red.circle.other.infra.database.rds.entity.gift.GiftConfig;
import com.red.circle.other.infra.database.rds.service.gift.GiftConfigService;
import com.red.circle.other.infra.database.rds.service.gift.GiftWallService;
import com.red.circle.other.inner.model.cmd.sys.GiftQryCmd;
import com.red.circle.other.infra.database.rds.entity.gift.GiftConfig;
import com.red.circle.other.infra.database.rds.service.gift.GiftConfigService;
import com.red.circle.other.infra.database.rds.service.gift.GiftWallService;
import com.red.circle.other.infra.enums.user.user.CpRelationshipType;
import com.red.circle.other.inner.enums.material.GiftTabEnum;
import com.red.circle.other.inner.model.cmd.sys.GiftQryCmd;
import com.red.circle.other.inner.model.dto.gift.UserGiftWallDTO;
import com.red.circle.other.inner.model.dto.material.GiftConfigDTO;
import java.sql.Timestamp;
@ -65,10 +67,11 @@ public class GiftConfigClientServiceImpl implements GiftConfigClientService {
return pageResult.convert(giftInnerConvertor::toGiftConfigDTO);
}
@Override
public Boolean updateGift(GiftConfigDTO giftConfigDTO) {
return giftConfigService.updateGift(giftInnerConvertor.toGiftConfig(giftConfigDTO));
}
@Override
public Boolean updateGift(GiftConfigDTO giftConfigDTO) {
return giftConfigService.updateGift(
normalizeCpRelationType(giftInnerConvertor.toGiftConfig(giftConfigDTO)));
}
@Override
public void removeGiftCache() {
@ -80,10 +83,20 @@ public class GiftConfigClientServiceImpl implements GiftConfigClientService {
gameLuckyGiftCacheService.removeRemainingInventory(id, standardId);
}
@Override
public Boolean saveGift(GiftConfigDTO giftConfig) {
return giftConfigService.save(giftInnerConvertor.toGiftConfig(giftConfig));
}
@Override
public Boolean saveGift(GiftConfigDTO giftConfig) {
return giftConfigService.save(normalizeCpRelationType(giftInnerConvertor.toGiftConfig(giftConfig)));
}
private GiftConfig normalizeCpRelationType(GiftConfig giftConfig) {
if (Objects.isNull(giftConfig)) {
return null;
}
if (!Objects.equals(giftConfig.getGiftTab(), GiftTabEnum.CP.name())) {
return giftConfig.setCpRelationType(null);
}
return giftConfig.setCpRelationType(CpRelationshipType.normalize(giftConfig.getCpRelationType()));
}
@Override
public Boolean switchDelStatus(Long id, Boolean status) {

View File

@ -367,24 +367,23 @@ public class TeamManualSalaryPaymentClientServiceImpl implements
List<TeamSalaryPayment> cyclePayments = listCyclePayments(salaryPaymentMap,
target.getUserId(), billBelong);
PaymentSummary paymentSummary = summarizePayments(cyclePayments);
PaymentSummary receivedPaymentSummary = summarizeReceivedPayments(
new ArrayList<>(salaryPaymentMap.values()), target.getUserId());
BigDecimal expectedMemberSalary = salaryValue(billTarget.getMemberSalary());
BigDecimal expectedAgentSalary = salaryValue(billTarget.getOwnSalary());
BigDecimal expectedSalary = expectedTotalSalary(billTarget);
BigDecimal payableSalary = expectedSalary.subtract(paymentSummary.getTotalIssuedSalary())
BigDecimal payableSalary = expectedSalary.subtract(receivedPaymentSummary.getTotalIssuedSalary())
.setScale(2, RoundingMode.DOWN);
BigDecimal payableMemberSalary = expectedMemberSalary
.subtract(paymentSummary.getMemberIssuedSalary())
.subtract(receivedPaymentSummary.getMemberIssuedSalary())
.setScale(2, RoundingMode.DOWN);
BigDecimal payableAgentSalary = expectedAgentSalary
.subtract(paymentSummary.getAgentIssuedSalary())
.subtract(receivedPaymentSummary.getAgentIssuedSalary())
.setScale(2, RoundingMode.DOWN);
boolean currentLevelSettled = areCurrentRolesSettled(cyclePayments, target.getUserId(), region,
billTarget, payableSalary);
List<PolicyPayment> policyPayments = buildSettlementPayments(policyManager, billTarget,
cyclePayments, target.getUserId(), region, paymentSummary, payableSalary,
cyclePayments, target.getUserId(), region, receivedPaymentSummary, payableSalary,
currentLevelSettled);
TeamManualSalaryPaymentDTO dto = new TeamManualSalaryPaymentDTO()

View File

@ -151,10 +151,10 @@ public class CpLocalFlowSmokeTest {
UserPair cpPair = findPair(candidates, 1, 0, "CP");
runCpGiftApplyBlessDismissFlow(cpPair);
UserPair brotherPair = findPair(candidates, 1, 1, "BROTHER");
UserPair brotherPair = findPair(candidates, 1, 0, "BROTHER");
runNoChargeApplyAndAgreeFlow(brotherPair, "BROTHER");
UserPair sistersPair = findPair(candidates, 0, 0, "SISTERS");
UserPair sistersPair = findPair(candidates, 0, 1, "SISTERS");
runNoChargeApplyAndAgreeFlow(sistersPair, "SISTERS");
}
@ -197,6 +197,36 @@ public class CpLocalFlowSmokeTest {
cpApplyService.getId(sameGenderPair.acceptUserId, sameGenderPair.sendUserId, "CP"));
}
@Test
public void cpGiftAutoApplyUsesGiftRelationType() {
List<BaseInfo> candidates = baseInfoService.query()
.select(BaseInfo::getId, BaseInfo::getUserSex, BaseInfo::getOriginSys,
BaseInfo::getCountryCode)
.eq(BaseInfo::getOriginSys, SYS_ORIGIN)
.in(BaseInfo::getUserSex, Arrays.asList(0, 1))
.orderByDesc(BaseInfo::getId)
.last("LIMIT 500")
.list();
assertFalse("local LIKEI candidates should not be empty", candidates.isEmpty());
assertGiftAutoApplyRelationType(findPair(candidates, 1, 0, "BROTHER"), "BROTHER");
assertGiftAutoApplyRelationType(findPair(candidates, 0, 1, "SISTERS"), "SISTERS");
}
private void assertGiftAutoApplyRelationType(UserPair pair, String relationType) {
boolean created = sendCpApplyCmdExe.autoCreateFromCpGift(pair.sendUserId,
pair.acceptUserId, SYS_ORIGIN, relationType);
assertTrue(relationType + " gift should auto create apply", created);
Long applyId = cpApplyService.getId(pair.acceptUserId, pair.sendUserId, relationType);
assertNotNull(relationType + " auto apply id", applyId);
createdApplyIds.add(applyId);
CpApply apply = cpApplyService.getById(applyId);
assertEquals(relationType, apply.getRelationType());
assertEquals(0, BigDecimal.ZERO.compareTo(apply.getApplyConsumeGold()));
}
private void runCpGiftApplyBlessDismissFlow(UserPair pair) throws Exception {
boolean created = sendCpApplyCmdExe.autoCreateFromCpGift(pair.sendUserId, pair.acceptUserId,
SYS_ORIGIN);
@ -394,14 +424,14 @@ public class CpLocalFlowSmokeTest {
String relationType) {
for (BaseInfo send : candidates) {
if (!Objects.equals(send.getUserSex(), sendSex) || hasWaitApply(send.getId(), relationType)
|| cpRelationshipService.countCp(send.getId()) >= 4) {
|| cpRelationshipService.countCp(send.getId(), relationType) >= relationMaxCount(relationType)) {
continue;
}
for (BaseInfo accept : candidates) {
if (Objects.equals(send.getId(), accept.getId())
|| !Objects.equals(accept.getUserSex(), acceptSex)
|| hasReceivedWaitApply(accept.getId(), relationType)
|| cpRelationshipService.countCp(accept.getId()) >= 4
|| cpRelationshipService.countCp(accept.getId(), relationType) >= relationMaxCount(relationType)
|| cpRelationshipService.existsCp(send.getId(), accept.getId(), relationType)) {
continue;
}
@ -417,6 +447,10 @@ public class CpLocalFlowSmokeTest {
return cpApplyService.existsNotProcessSendApply(sendUserId, relationType);
}
private int relationMaxCount(String relationType) {
return Objects.equals("CP", relationType) ? 1 : 3;
}
private boolean hasReceivedWaitApply(Long acceptUserId, String relationType) {
return cpApplyService.query()
.eq(CpApply::getAcceptApplyUserId, acceptUserId)

View File

@ -0,0 +1,7 @@
ALTER TABLE `sys_gift_config`
ADD COLUMN `cp_relation_type` varchar(32) DEFAULT NULL COMMENT 'CP礼物关系类型CP/BROTHER/SISTERS' AFTER `gift_tab`;
UPDATE `sys_gift_config`
SET `cp_relation_type` = 'CP'
WHERE `gift_tab` = 'CP'
AND (`cp_relation_type` IS NULL OR `cp_relation_type` = '');