From 3f59e5b65323e47f653945cef93a55f4fe37d788 Mon Sep 17 00:00:00 2001 From: hy001 Date: Thu, 21 May 2026 15:43:38 +0800 Subject: [PATCH] CP --- .../model/event/gift/GiveGiftConfig.java | 17 ++- .../model/dto/material/GiftConfigDTO.java | 23 ++-- .../dto/clienobject/sys/SysGiftConfigCO.java | 23 ++-- .../app/command/user/ProcessCpApplyCmd.java | 56 +++++---- .../app/command/user/SendCpApplyCmdExe.java | 46 +++++--- .../convertor/material/GiftAppConvertor.java | 11 +- .../app/listener/gift/GiveGiftsListener.java | 13 ++- .../gift/strategy/GiftCountStrategy.java | 18 +-- .../command/user/SendCpApplyCmdExeTest.java | 110 ++++++++++++++++++ .../dto/clientobject/gift/GiftConfigCO.java | 23 ++-- .../database/mongo/entity/gift/GiftValue.java | 23 ++-- .../database/rds/entity/gift/GiftConfig.java | 28 +++-- .../gift/impl/GiftConfigServiceImpl.java | 40 ++++--- .../user/user/CpRelationshipService.java | 25 ++-- .../user/impl/CpRelationshipServiceImpl.java | 24 ++-- .../enums/user/user/CpRelationshipType.java | 10 +- .../user/user/CpRelationshipTypeTest.java | 30 +++++ .../impl/GiftConfigClientServiceImpl.java | 37 ++++-- ...mManualSalaryPaymentClientServiceImpl.java | 9 +- .../src/test/java/CpLocalFlowSmokeTest.java | 42 ++++++- ...60521_sys_gift_config_cp_relation_type.sql | 7 ++ 21 files changed, 448 insertions(+), 167 deletions(-) create mode 100644 rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/user/SendCpApplyCmdExeTest.java create mode 100644 rc-service/rc-service-other/other-infrastructure/src/test/java/com/red/circle/other/infra/enums/user/user/CpRelationshipTypeTest.java create mode 100644 sql/20260521_sys_gift_config_cp_relation_type.sql diff --git a/rc-common-business/common-business-mq/business-mq-model/src/main/java/com/red/circle/mq/business/model/event/gift/GiveGiftConfig.java b/rc-common-business/common-business-mq/business-mq-model/src/main/java/com/red/circle/mq/business/model/event/gift/GiveGiftConfig.java index 29086e06..975e7bf1 100644 --- a/rc-common-business/common-business-mq/business-mq-model/src/main/java/com/red/circle/mq/business/model/event/gift/GiveGiftConfig.java +++ b/rc-common-business/common-business-mq/business-mq-model/src/main/java/com/red/circle/mq/business/model/event/gift/GiveGiftConfig.java @@ -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; + +} diff --git a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/material/GiftConfigDTO.java b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/material/GiftConfigDTO.java index 57996ecb..12b35161 100644 --- a/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/material/GiftConfigDTO.java +++ b/rc-service/rc-inner-api/other-inner/other-inner-model/src/main/java/com/red/circle/other/inner/model/dto/material/GiftConfigDTO.java @@ -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. diff --git a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/clienobject/sys/SysGiftConfigCO.java b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/clienobject/sys/SysGiftConfigCO.java index f1f04887..379d1aa3 100644 --- a/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/clienobject/sys/SysGiftConfigCO.java +++ b/rc-service/rc-service-console/console-client/src/main/java/com/red/circle/console/app/dto/clienobject/sys/SysGiftConfigCO.java @@ -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. diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/ProcessCpApplyCmd.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/ProcessCpApplyCmd.java index 63b256ef..8a54645d 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/ProcessCpApplyCmd.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/ProcessCpApplyCmd.java @@ -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()) diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/SendCpApplyCmdExe.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/SendCpApplyCmdExe.java index 599bf23d..ecb456df 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/SendCpApplyCmdExe.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/command/user/SendCpApplyCmdExe.java @@ -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())); } diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/convertor/material/GiftAppConvertor.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/convertor/material/GiftAppConvertor.java index f7cbebbd..675507ef 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/convertor/material/GiftAppConvertor.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/convertor/material/GiftAppConvertor.java @@ -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) { diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/GiveGiftsListener.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/GiveGiftsListener.java index 580b2af8..42b35928 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/GiveGiftsListener.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/GiveGiftsListener.java @@ -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() diff --git a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/strategy/GiftCountStrategy.java b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/strategy/GiftCountStrategy.java index a2adf6ea..7ee7fbd1 100644 --- a/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/strategy/GiftCountStrategy.java +++ b/rc-service/rc-service-other/other-application/src/main/java/com/red/circle/other/app/listener/gift/strategy/GiftCountStrategy.java @@ -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={}", diff --git a/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/user/SendCpApplyCmdExeTest.java b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/user/SendCpApplyCmdExeTest.java new file mode 100644 index 00000000..d2b1f809 --- /dev/null +++ b/rc-service/rc-service-other/other-application/src/test/java/com/red/circle/other/app/command/user/SendCpApplyCmdExeTest.java @@ -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 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; + } + } +} diff --git a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/gift/GiftConfigCO.java b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/gift/GiftConfigCO.java index c8ff7d2b..a846a30e 100644 --- a/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/gift/GiftConfigCO.java +++ b/rc-service/rc-service-other/other-client/src/main/java/com/red/circle/other/app/dto/clientobject/gift/GiftConfigCO.java @@ -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; /** diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/gift/GiftValue.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/gift/GiftValue.java index 2b6b241a..8ea60c34 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/gift/GiftValue.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/mongo/entity/gift/GiftValue.java @@ -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; /** * 发送礼物数量. diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/gift/GiftConfig.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/gift/GiftConfig.java index f5c1ed20..b0e61222 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/gift/GiftConfig.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/entity/gift/GiftConfig.java @@ -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. diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/gift/impl/GiftConfigServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/gift/impl/GiftConfigServiceImpl.java index 432c6d9a..2d04370b 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/gift/impl/GiftConfigServiceImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/gift/impl/GiftConfigServiceImpl.java @@ -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 { */ 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 diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/user/user/impl/CpRelationshipServiceImpl.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/user/user/impl/CpRelationshipServiceImpl.java index 7056b63b..9c67e217 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/user/user/impl/CpRelationshipServiceImpl.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/database/rds/service/user/user/impl/CpRelationshipServiceImpl.java @@ -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()); diff --git a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/user/user/CpRelationshipType.java b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/user/user/CpRelationshipType.java index 822a24f5..87e5f0de 100644 --- a/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/user/user/CpRelationshipType.java +++ b/rc-service/rc-service-other/other-infrastructure/src/main/java/com/red/circle/other/infra/enums/user/user/CpRelationshipType.java @@ -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; }; } diff --git a/rc-service/rc-service-other/other-infrastructure/src/test/java/com/red/circle/other/infra/enums/user/user/CpRelationshipTypeTest.java b/rc-service/rc-service-other/other-infrastructure/src/test/java/com/red/circle/other/infra/enums/user/user/CpRelationshipTypeTest.java new file mode 100644 index 00000000..a9e56f41 --- /dev/null +++ b/rc-service/rc-service-other/other-infrastructure/src/test/java/com/red/circle/other/infra/enums/user/user/CpRelationshipTypeTest.java @@ -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)); + } +} diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/material/gift/impl/GiftConfigClientServiceImpl.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/material/gift/impl/GiftConfigClientServiceImpl.java index f2f97d5a..6017151f 100644 --- a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/material/gift/impl/GiftConfigClientServiceImpl.java +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/material/gift/impl/GiftConfigClientServiceImpl.java @@ -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) { diff --git a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/team/impl/TeamManualSalaryPaymentClientServiceImpl.java b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/team/impl/TeamManualSalaryPaymentClientServiceImpl.java index 5e16179e..d9cdcace 100644 --- a/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/team/impl/TeamManualSalaryPaymentClientServiceImpl.java +++ b/rc-service/rc-service-other/other-inner-endpoint/src/main/java/com/red/circle/other/app/inner/service/team/impl/TeamManualSalaryPaymentClientServiceImpl.java @@ -367,24 +367,23 @@ public class TeamManualSalaryPaymentClientServiceImpl implements List 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 policyPayments = buildSettlementPayments(policyManager, billTarget, - cyclePayments, target.getUserId(), region, paymentSummary, payableSalary, + cyclePayments, target.getUserId(), region, receivedPaymentSummary, payableSalary, currentLevelSettled); TeamManualSalaryPaymentDTO dto = new TeamManualSalaryPaymentDTO() diff --git a/rc-service/rc-service-other/other-start/src/test/java/CpLocalFlowSmokeTest.java b/rc-service/rc-service-other/other-start/src/test/java/CpLocalFlowSmokeTest.java index 2028d7fe..a1d9e6f4 100644 --- a/rc-service/rc-service-other/other-start/src/test/java/CpLocalFlowSmokeTest.java +++ b/rc-service/rc-service-other/other-start/src/test/java/CpLocalFlowSmokeTest.java @@ -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 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) diff --git a/sql/20260521_sys_gift_config_cp_relation_type.sql b/sql/20260521_sys_gift_config_cp_relation_type.sql new file mode 100644 index 00000000..ebd35952 --- /dev/null +++ b/sql/20260521_sys_gift_config_cp_relation_type.sql @@ -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` = '');