修复边界

This commit is contained in:
hy001 2026-05-23 14:02:23 +08:00
parent 3588d0aeee
commit fa6b9be148
8 changed files with 270 additions and 157 deletions

View File

@ -1,11 +1,8 @@
package com.red.circle.other.app.command.user; package com.red.circle.other.app.command.user;
import com.red.circle.common.business.core.enums.SysOriginPlatformEnum;
import com.red.circle.external.inner.endpoint.message.ImMessageClient; import com.red.circle.external.inner.endpoint.message.ImMessageClient;
import com.red.circle.framework.core.asserts.ResponseAssert; import com.red.circle.framework.core.asserts.ResponseAssert;
import com.red.circle.framework.core.response.CommonErrorCode; import com.red.circle.framework.core.response.CommonErrorCode;
import com.red.circle.mq.business.model.event.user.CpApplyEvent;
import com.red.circle.mq.rocket.business.producer.UserMqMessageService;
import com.red.circle.other.app.common.cp.CpRelationC2cNoticeUtils; import com.red.circle.other.app.common.cp.CpRelationC2cNoticeUtils;
import com.red.circle.other.app.common.cp.CpRelationBroadcastMqClient; import com.red.circle.other.app.common.cp.CpRelationBroadcastMqClient;
import com.red.circle.other.app.dto.cmd.user.relation.cp.ProcessApplyCmd; import com.red.circle.other.app.dto.cmd.user.relation.cp.ProcessApplyCmd;
@ -20,14 +17,12 @@ import com.red.circle.other.infra.database.rds.service.user.user.CpRelationshipS
import com.red.circle.other.infra.database.rds.service.user.user.CpValueService; import com.red.circle.other.infra.database.rds.service.user.user.CpValueService;
import com.red.circle.other.infra.enums.user.user.CpApplyStatus; import com.red.circle.other.infra.enums.user.user.CpApplyStatus;
import com.red.circle.other.infra.enums.user.user.CpRelationshipType; import com.red.circle.other.infra.enums.user.user.CpRelationshipType;
import com.red.circle.tool.core.date.TimestampUtils;
import com.red.circle.other.inner.asserts.user.UserRelationErrorCode; import com.red.circle.other.inner.asserts.user.UserRelationErrorCode;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.util.Arrays; import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -49,8 +44,6 @@ public class ProcessCpApplyCmd {
private final CpApplyService cpApplyService; private final CpApplyService cpApplyService;
private final CpValueService cpValueService; private final CpValueService cpValueService;
private final ImMessageClient imMessageClient; private final ImMessageClient imMessageClient;
private final WalletGoldClient walletGoldClient;
private final UserMqMessageService userMqMessageService;
private final CpRelationshipService cpRelationshipService; private final CpRelationshipService cpRelationshipService;
private final UserProfileGateway userProfileGateway; private final UserProfileGateway userProfileGateway;
private final CpRelationshipCacheService cpRelationshipCacheService; private final CpRelationshipCacheService cpRelationshipCacheService;
@ -98,7 +91,6 @@ public class ProcessCpApplyCmd {
cpApplyService.changeStatusById(cmd.getApplyId(), getStatus(cmd))); cpApplyService.changeStatusById(cmd.getApplyId(), getStatus(cmd)));
if (!agree) { if (!agree) {
returnGoldCoins(cmd, cpApply);
sendProcessNotice(cpApply, false); sendProcessNotice(cpApply, false);
return; return;
} }
@ -114,12 +106,7 @@ public class ProcessCpApplyCmd {
cmd.requireReqSysOrigin(), relationType); cmd.requireReqSysOrigin(), relationType);
} }
List<Long> refusedApplyIds = cpApplyService.refuseOtherWaitBetweenUsers(cpApply.getId(), sendAutoRejectedNotices(autoRefuseWaitAppliesAfterAgree(cpApply, relationType));
cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId());
boolean refusedByLimit = refuseStatusWaitIfLimitReached(cmd, cpApply, relationType);
if (!refusedApplyIds.isEmpty() || refusedByLimit) {
scheduleReimburse(cmd, cpApply.getId());
}
cpRelationshipCacheService.remove(Arrays.asList(cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId())); cpRelationshipCacheService.remove(Arrays.asList(cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId()));
cpRelationBroadcastMqClient.publish(cmd.requireReqSysOrigin(), cpApply.getId(), cpRelationBroadcastMqClient.publish(cmd.requireReqSysOrigin(), cpApply.getId(),
@ -145,22 +132,45 @@ public class ProcessCpApplyCmd {
} }
} }
private boolean refuseStatusWaitIfLimitReached(ProcessApplyCmd cmd, CpApply cpApply, private void sendAutoRejectedNotices(List<CpApply> refusedApplies) {
String relationType) { if (Objects.isNull(refusedApplies) || refusedApplies.isEmpty()) {
if (cpRelationshipService.countCp(cpApply.getAcceptApplyUserId(), relationType) return;
< relationMaxCount(relationType)) {
return false;
} }
cpApplyService.refuseStatusWait(cmd.requiredReqUserId(), relationType); refusedApplies.forEach(apply -> sendProcessNotice(apply, false));
return true;
} }
private void scheduleReimburse(ProcessApplyCmd cmd, Long applyId) { private List<CpApply> autoRefuseWaitAppliesAfterAgree(CpApply cpApply, String relationType) {
userMqMessageService.cpApplyDelayed( Map<Long, CpApply> refusedApplyMap = new LinkedHashMap<>();
new CpApplyEvent() addRefusedApplies(refusedApplyMap,
.setId(applyId) cpApplyService.refuseOtherWaitAppliesBetweenUsers(cpApply.getId(),
.setSysOrigin(SysOriginPlatformEnum.valueOf(cmd.requireReqSysOrigin())), cpApply.getSendApplyUserId(), cpApply.getAcceptApplyUserId()));
TimestampUtils.nowPlusMinutes(1)); addRefusedApplies(refusedApplyMap,
refuseWaitAppliesIfLimitReached(cpApply, cpApply.getSendApplyUserId(), relationType));
addRefusedApplies(refusedApplyMap,
refuseWaitAppliesIfLimitReached(cpApply, cpApply.getAcceptApplyUserId(), relationType));
return List.copyOf(refusedApplyMap.values());
}
private List<CpApply> refuseWaitAppliesIfLimitReached(CpApply cpApply, Long userId,
String relationType) {
if (cpRelationshipService.countCp(userId, relationType) < relationMaxCount(relationType)) {
return List.of();
}
List<CpApply> refusedApplies = cpApplyService.refuseWaitAppliesByUserAndRelation(
cpApply.getId(), userId, relationType);
log.info("[CP] auto refused wait applies after relation limit reached, userId={}, relationType={}, applyIds={}",
userId, relationType, refusedApplies.stream().map(CpApply::getId).toList());
return refusedApplies;
}
private void addRefusedApplies(Map<Long, CpApply> applyMap, List<CpApply> applies) {
if (Objects.isNull(applies) || applies.isEmpty()) {
return;
}
applies.stream()
.filter(Objects::nonNull)
.filter(apply -> Objects.nonNull(apply.getId()))
.forEach(apply -> applyMap.putIfAbsent(apply.getId(), apply));
} }
private int relationMaxCount(String relationType) { private int relationMaxCount(String relationType) {
@ -169,23 +179,6 @@ public class ProcessCpApplyCmd {
: FRIEND_MAX_COUNT; : FRIEND_MAX_COUNT;
} }
private void returnGoldCoins(ProcessApplyCmd cmd, CpApply cpApply) {
if (Objects.isNull(cpApply.getApplyConsumeGold())
|| cpApply.getApplyConsumeGold().compareTo(BigDecimal.ZERO) <= 0) {
cpApplyService.changeStatusById(cmd.getApplyId(), CpApplyStatus.REIMBURSE);
return;
}
walletGoldClient.changeBalance(GoldReceiptCmd.builder()
.appIncome()
.userId(cpApply.getSendApplyUserId())
.eventId(cpApply.getId())
.sysOrigin(cmd.requireReqSysOrigin())
.origin(GoldOrigin.CP_BUILD)
.amount(cpApply.getApplyConsumeGold())
.build());
cpApplyService.changeStatusById(cmd.getApplyId(), CpApplyStatus.REIMBURSE);
}
private Long createCpValue() { private Long createCpValue() {
CpValue cpValue = new CpValue() CpValue cpValue = new CpValue()
.setCpVal(BigDecimal.ZERO); .setCpVal(BigDecimal.ZERO);

View File

@ -12,17 +12,10 @@ import com.red.circle.mq.rocket.business.streams.CpApplySink;
import com.red.circle.other.app.common.cp.CpRelationC2cNoticeUtils; import com.red.circle.other.app.common.cp.CpRelationC2cNoticeUtils;
import com.red.circle.other.domain.gateway.user.UserProfileGateway; import com.red.circle.other.domain.gateway.user.UserProfileGateway;
import com.red.circle.other.domain.model.user.UserProfile; import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.tool.core.collection.CollectionUtils;
import com.red.circle.tool.core.json.JacksonUtils; import com.red.circle.tool.core.json.JacksonUtils;
import com.red.circle.other.infra.database.rds.entity.user.user.CpApply; 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.CpApplyService;
import com.red.circle.other.infra.enums.user.user.CpApplyStatus; import com.red.circle.other.infra.enums.user.user.CpApplyStatus;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import com.red.circle.wallet.inner.model.cmd.GoldReceiptCmd;
import com.red.circle.wallet.inner.model.enums.GoldOrigin;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects; import java.util.Objects;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -40,7 +33,6 @@ public class CpApplyListener implements MessageListener {
private final CpApplyService cpApplyService; private final CpApplyService cpApplyService;
private final ImMessageClient imMessageClient; private final ImMessageClient imMessageClient;
private final UserProfileGateway userProfileGateway; private final UserProfileGateway userProfileGateway;
private final WalletGoldClient walletGoldClient;
private final MessageEventProcess messageEventProcess; private final MessageEventProcess messageEventProcess;
@Override @Override
@ -61,58 +53,16 @@ public class CpApplyListener implements MessageListener {
return; return;
} }
// 同意检测那些被拒绝都
if (Objects.equals(cpApply.getStatus(), CpApplyStatus.AGREE.name())) {
checkReimburse(eventBody, cpApply);
return;
}
// 等待超时 // 等待超时
if (Objects.equals(cpApply.getStatus(), CpApplyStatus.WAIT.name())) { if (Objects.equals(cpApply.getStatus(), CpApplyStatus.WAIT.name())) {
reimburse(eventBody, cpApply, true); expire(cpApply);
} }
}); });
} }
private void checkReimburse(CpApplyEvent param, CpApply cpApply) { private void expire(CpApply cpApply) {
Map<Long, CpApply> applyMap = new LinkedHashMap<>(); sendExpiredNotice(cpApply);
addReimburseApplies(applyMap, cpApplyService.listRefuse(cpApply.getAcceptApplyUserId())); cpApplyService.changeStatusById(cpApply.getId(), CpApplyStatus.EXPIRE);
addReimburseApplies(applyMap, cpApplyService.listRefuseBetweenUsers(cpApply.getSendApplyUserId(),
cpApply.getAcceptApplyUserId()));
if (applyMap.isEmpty()) {
return;
}
applyMap.values().forEach(apply -> reimburse(param, apply, false));
}
private void addReimburseApplies(Map<Long, CpApply> applyMap, List<CpApply> cpApplies) {
if (CollectionUtils.isEmpty(cpApplies)) {
return;
}
cpApplies.stream()
.filter(Objects::nonNull)
.filter(apply -> Objects.nonNull(apply.getId()))
.forEach(apply -> applyMap.putIfAbsent(apply.getId(), apply));
}
private void reimburse(CpApplyEvent param, CpApply cpApply, boolean expired) {
if (expired) {
sendExpiredNotice(cpApply);
}
if (Objects.isNull(cpApply.getApplyConsumeGold())
|| cpApply.getApplyConsumeGold().signum() <= 0) {
cpApplyService.changeStatusById(cpApply.getId(), CpApplyStatus.REIMBURSE);
return;
}
walletGoldClient.changeBalance(GoldReceiptCmd.builder()
.appIncome()
.userId(cpApply.getSendApplyUserId())
.eventId(cpApply.getId())
.sysOrigin(param.getSysOrigin())
.origin(GoldOrigin.CP_BUILD)
.amount(cpApply.getApplyConsumeGold())
.build());
cpApplyService.changeStatusById(cpApply.getId(), CpApplyStatus.REIMBURSE);
} }
private void sendExpiredNotice(CpApply cpApply) { private void sendExpiredNotice(CpApply cpApply) {

View File

@ -12,8 +12,6 @@ import com.red.circle.external.inner.endpoint.message.ImMessageClient;
import com.red.circle.external.inner.model.cmd.message.CustomC2cMsgBodyCmd; import com.red.circle.external.inner.model.cmd.message.CustomC2cMsgBodyCmd;
import com.red.circle.framework.core.dto.ReqSysOrigin; import com.red.circle.framework.core.dto.ReqSysOrigin;
import com.red.circle.framework.dto.ResultResponse; import com.red.circle.framework.dto.ResultResponse;
import com.red.circle.mq.business.model.event.user.CpApplyEvent;
import com.red.circle.mq.rocket.business.producer.UserMqMessageService;
import com.red.circle.other.app.common.cp.CpRelationBroadcastMqClient; import com.red.circle.other.app.common.cp.CpRelationBroadcastMqClient;
import com.red.circle.other.app.dto.cmd.user.relation.cp.ProcessApplyCmd; import com.red.circle.other.app.dto.cmd.user.relation.cp.ProcessApplyCmd;
import com.red.circle.other.domain.gateway.user.UserProfileGateway; import com.red.circle.other.domain.gateway.user.UserProfileGateway;
@ -24,8 +22,6 @@ 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.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.CpValueService;
import com.red.circle.other.infra.enums.user.user.CpApplyStatus; import com.red.circle.other.infra.enums.user.user.CpApplyStatus;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import java.sql.Timestamp;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Assertions;
@ -91,16 +87,108 @@ class ProcessCpApplyCmdTest {
@Test @Test
void agreeApplyShouldRejectOtherWaitAppliesBetweenSameUsers() { void agreeApplyShouldRejectOtherWaitAppliesBetweenSameUsers() {
Fixture fixture = new Fixture("CP"); Fixture fixture = new Fixture("CP");
when(fixture.cpApplyService.refuseOtherWaitBetweenUsers(3001L, 1001L, 2001L)) when(fixture.cpApplyService.refuseOtherWaitAppliesBetweenUsers(3001L, 1001L, 2001L))
.thenReturn(List.of(3002L, 3003L)); .thenReturn(List.of(apply(3002L, "BROTHER"), apply(3003L, "SISTERS")));
fixture.exe.execute(processCmd(true)); fixture.exe.execute(processCmd(true));
verify(fixture.cpApplyService).refuseOtherWaitBetweenUsers(3001L, 1001L, 2001L); verify(fixture.cpApplyService).refuseOtherWaitAppliesBetweenUsers(3001L, 1001L, 2001L);
ArgumentCaptor<CpApplyEvent> eventCaptor = ArgumentCaptor.forClass(CpApplyEvent.class); List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(3);
verify(fixture.userMqMessageService).cpApplyDelayed(eventCaptor.capture(), assertProcessMessage(messages.get(0), "RELATION_REJECTED", "REJECTED", false, "BROTHER",
any(Timestamp.class)); 3002L);
Assertions.assertEquals(3001L, eventCaptor.getValue().getId()); assertProcessMessage(messages.get(1), "RELATION_REJECTED", "REJECTED", false, "SISTERS",
3003L);
assertProcessMessage(messages.get(2), "RELATION_ESTABLISHED", "ACCEPTED", true, "CP",
3001L);
}
@Test
void agreeCpApplyShouldRejectPairOtherRelationAppliesAndSenderOtherCpApplies() {
Fixture fixture = new Fixture("CP");
fixture.mockProfile(4001L);
fixture.mockProfile(4002L);
when(fixture.cpRelationshipService.countCp(1001L, "CP")).thenReturn(0, 1);
when(fixture.cpRelationshipService.countCp(2001L, "CP")).thenReturn(0, 1);
when(fixture.cpApplyService.refuseOtherWaitAppliesBetweenUsers(3001L, 1001L, 2001L))
.thenReturn(List.of(apply(3002L, "BROTHER"), apply(3003L, "SISTERS")));
when(fixture.cpApplyService.refuseWaitAppliesByUserAndRelation(3001L, 1001L, "CP"))
.thenReturn(List.of(
apply(3004L, 1001L, 4001L, "CP"),
apply(3005L, 1001L, 4002L, "CP")));
fixture.exe.execute(processCmd(true));
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(5);
assertProcessMessage(messages.get(0), "RELATION_REJECTED", "REJECTED", false, "BROTHER",
3002L);
assertProcessMessage(messages.get(1), "RELATION_REJECTED", "REJECTED", false, "SISTERS",
3003L);
assertProcessMessage(messages.get(2), "RELATION_REJECTED", "REJECTED", false, "CP",
3004L, "4001", "1001");
assertProcessMessage(messages.get(3), "RELATION_REJECTED", "REJECTED", false, "CP",
3005L, "4002", "1001");
assertProcessMessage(messages.get(4), "RELATION_ESTABLISHED", "ACCEPTED", true, "CP",
3001L);
}
@Test
void agreeCpApplyShouldRejectSenderOtherCpAppliesWhenCpLimitReached() {
Fixture fixture = new Fixture("CP");
fixture.mockProfile(4001L);
fixture.mockProfile(4002L);
when(fixture.cpRelationshipService.countCp(1001L, "CP")).thenReturn(0, 1);
when(fixture.cpRelationshipService.countCp(2001L, "CP")).thenReturn(0, 1);
when(fixture.cpApplyService.refuseWaitAppliesByUserAndRelation(3001L, 1001L, "CP"))
.thenReturn(List.of(
apply(3002L, 1001L, 4001L, "CP"),
apply(3003L, 1001L, 4002L, "CP")));
fixture.exe.execute(processCmd(true));
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(3);
assertProcessMessage(messages.get(0), "RELATION_REJECTED", "REJECTED", false, "CP",
3002L, "4001", "1001");
assertProcessMessage(messages.get(1), "RELATION_REJECTED", "REJECTED", false, "CP",
3003L, "4002", "1001");
assertProcessMessage(messages.get(2), "RELATION_ESTABLISHED", "ACCEPTED", true, "CP",
3001L);
}
@Test
void agreeBrotherApplyShouldNotRejectOtherBrotherAppliesBeforeLimitReached() {
Fixture fixture = new Fixture("BROTHER");
when(fixture.cpRelationshipService.countCp(1001L, "BROTHER")).thenReturn(1, 2);
when(fixture.cpRelationshipService.countCp(2001L, "BROTHER")).thenReturn(0, 1);
fixture.exe.execute(processCmd(true));
verify(fixture.cpApplyService, never()).refuseWaitAppliesByUserAndRelation(
any(Long.class), eq(1001L), eq("BROTHER"));
assertProcessMessage(fixture.sentCustomMessage(), "RELATION_ESTABLISHED", "ACCEPTED",
true, "BROTHER");
}
@Test
void agreeBrotherApplyShouldRejectSenderOtherBrotherAppliesWhenLimitReached() {
Fixture fixture = new Fixture("BROTHER");
fixture.mockProfile(4001L);
fixture.mockProfile(4002L);
when(fixture.cpRelationshipService.countCp(1001L, "BROTHER")).thenReturn(2, 3);
when(fixture.cpRelationshipService.countCp(2001L, "BROTHER")).thenReturn(0, 1);
when(fixture.cpApplyService.refuseWaitAppliesByUserAndRelation(3001L, 1001L, "BROTHER"))
.thenReturn(List.of(
apply(3002L, 1001L, 4001L, "BROTHER"),
apply(3003L, 1001L, 4002L, "BROTHER")));
fixture.exe.execute(processCmd(true));
List<CustomC2cMsgBodyCmd> messages = fixture.sentCustomMessages(3);
assertProcessMessage(messages.get(0), "RELATION_REJECTED", "REJECTED", false, "BROTHER",
3002L, "4001", "1001");
assertProcessMessage(messages.get(1), "RELATION_REJECTED", "REJECTED", false, "BROTHER",
3003L, "4002", "1001");
assertProcessMessage(messages.get(2), "RELATION_ESTABLISHED", "ACCEPTED", true, "BROTHER",
3001L);
} }
private static ProcessApplyCmd processCmd(boolean agree) { private static ProcessApplyCmd processCmd(boolean agree) {
@ -113,10 +201,19 @@ class ProcessCpApplyCmdTest {
} }
private static CpApply apply(String relationType) { private static CpApply apply(String relationType) {
return apply(3001L, relationType);
}
private static CpApply apply(Long applyId, String relationType) {
return apply(applyId, 1001L, 2001L, relationType);
}
private static CpApply apply(Long applyId, Long sendUserId, Long acceptUserId,
String relationType) {
return new CpApply() return new CpApply()
.setId(3001L) .setId(applyId)
.setSendApplyUserId(1001L) .setSendApplyUserId(sendUserId)
.setAcceptApplyUserId(2001L) .setAcceptApplyUserId(acceptUserId)
.setRelationType(relationType) .setRelationType(relationType)
.setStatus(CpApplyStatus.WAIT.name()); .setStatus(CpApplyStatus.WAIT.name());
} }
@ -124,8 +221,21 @@ class ProcessCpApplyCmdTest {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private static void assertProcessMessage(CustomC2cMsgBodyCmd message, String action, private static void assertProcessMessage(CustomC2cMsgBodyCmd message, String action,
String status, Boolean agree, String relationType) { String status, Boolean agree, String relationType) {
Assertions.assertEquals("2001", message.getFromAccount()); assertProcessMessage(message, action, status, agree, relationType, 3001L);
Assertions.assertEquals("1001", message.getToAccount()); }
@SuppressWarnings("unchecked")
private static void assertProcessMessage(CustomC2cMsgBodyCmd message, String action,
String status, Boolean agree, String relationType, Long applyId) {
assertProcessMessage(message, action, status, agree, relationType, applyId, "2001", "1001");
}
@SuppressWarnings("unchecked")
private static void assertProcessMessage(CustomC2cMsgBodyCmd message, String action,
String status, Boolean agree, String relationType, Long applyId, String fromAccount,
String toAccount) {
Assertions.assertEquals(fromAccount, message.getFromAccount());
Assertions.assertEquals(toAccount, message.getToAccount());
Assertions.assertEquals("CP_BUILD", message.getDesc()); Assertions.assertEquals("CP_BUILD", message.getDesc());
Map<String, Object> data = (Map<String, Object>) message.getData(); Map<String, Object> data = (Map<String, Object>) message.getData();
Assertions.assertEquals("CP_BUILD", data.get("noticeType")); Assertions.assertEquals("CP_BUILD", data.get("noticeType"));
@ -135,7 +245,7 @@ class ProcessCpApplyCmdTest {
Assertions.assertEquals(status, data.get("result")); Assertions.assertEquals(status, data.get("result"));
Assertions.assertEquals(status, data.get("state")); Assertions.assertEquals(status, data.get("state"));
Assertions.assertEquals(agree, data.get("agree")); Assertions.assertEquals(agree, data.get("agree"));
Assertions.assertEquals(3001L, data.get("applyId")); Assertions.assertEquals(applyId, data.get("applyId"));
Assertions.assertEquals(relationType, data.get("relationType")); Assertions.assertEquals(relationType, data.get("relationType"));
Assertions.assertTrue(data.get("content").toString() Assertions.assertTrue(data.get("content").toString()
.contains("\"relationType\":\"" + relationType + "\"")); .contains("\"relationType\":\"" + relationType + "\""));
@ -148,21 +258,18 @@ class ProcessCpApplyCmdTest {
private final CpRelationBroadcastMqClient cpRelationBroadcastMqClient = mock( private final CpRelationBroadcastMqClient cpRelationBroadcastMqClient = mock(
CpRelationBroadcastMqClient.class); CpRelationBroadcastMqClient.class);
private final ImMessageClient imMessageClient = mock(ImMessageClient.class); private final ImMessageClient imMessageClient = mock(ImMessageClient.class);
private final UserMqMessageService userMqMessageService = mock(UserMqMessageService.class); private final UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
private final ProcessCpApplyCmd exe; private final ProcessCpApplyCmd exe;
private Fixture(String relationType) { private Fixture(String relationType) {
CpValueService cpValueService = mock(CpValueService.class); CpValueService cpValueService = mock(CpValueService.class);
WalletGoldClient walletGoldClient = mock(WalletGoldClient.class);
UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
CpRelationshipCacheService cpRelationshipCacheService = mock( CpRelationshipCacheService cpRelationshipCacheService = mock(
CpRelationshipCacheService.class); CpRelationshipCacheService.class);
when(cpApplyService.getById(3001L)).thenReturn(apply(relationType)); when(cpApplyService.getById(3001L)).thenReturn(apply(relationType));
when(cpApplyService.changeStatusById(3001L, CpApplyStatus.AGREE)).thenReturn(true); when(cpApplyService.changeStatusById(3001L, CpApplyStatus.AGREE)).thenReturn(true);
when(cpApplyService.changeStatusById(3001L, CpApplyStatus.REFUSE)).thenReturn(true); when(cpApplyService.changeStatusById(3001L, CpApplyStatus.REFUSE)).thenReturn(true);
when(cpApplyService.changeStatusById(3001L, CpApplyStatus.REIMBURSE)).thenReturn(true); when(cpApplyService.refuseOtherWaitAppliesBetweenUsers(3001L, 1001L, 2001L))
when(cpApplyService.refuseOtherWaitBetweenUsers(3001L, 1001L, 2001L))
.thenReturn(List.of()); .thenReturn(List.of());
when(userProfileGateway.getByUserId(1001L)).thenReturn(profile(1001L)); when(userProfileGateway.getByUserId(1001L)).thenReturn(profile(1001L));
when(userProfileGateway.getByUserId(2001L)).thenReturn(profile(2001L)); when(userProfileGateway.getByUserId(2001L)).thenReturn(profile(2001L));
@ -173,14 +280,16 @@ class ProcessCpApplyCmdTest {
cpApplyService, cpApplyService,
cpValueService, cpValueService,
imMessageClient, imMessageClient,
walletGoldClient,
userMqMessageService,
cpRelationshipService, cpRelationshipService,
userProfileGateway, userProfileGateway,
cpRelationshipCacheService, cpRelationshipCacheService,
cpRelationBroadcastMqClient); cpRelationBroadcastMqClient);
} }
private void mockProfile(Long userId) {
when(userProfileGateway.getByUserId(userId)).thenReturn(profile(userId));
}
private CustomC2cMsgBodyCmd sentCustomMessage() { private CustomC2cMsgBodyCmd sentCustomMessage() {
ArgumentCaptor<CustomC2cMsgBodyCmd> captor = ArgumentCaptor.forClass( ArgumentCaptor<CustomC2cMsgBodyCmd> captor = ArgumentCaptor.forClass(
CustomC2cMsgBodyCmd.class); CustomC2cMsgBodyCmd.class);
@ -188,6 +297,13 @@ class ProcessCpApplyCmdTest {
return captor.getValue(); return captor.getValue();
} }
private List<CustomC2cMsgBodyCmd> sentCustomMessages(int count) {
ArgumentCaptor<CustomC2cMsgBodyCmd> captor = ArgumentCaptor.forClass(
CustomC2cMsgBodyCmd.class);
verify(imMessageClient, org.mockito.Mockito.times(count)).sendCustomMessage(captor.capture());
return captor.getAllValues();
}
private static UserProfile profile(Long userId) { private static UserProfile profile(Long userId) {
UserProfile userProfile = new UserProfile(); UserProfile userProfile = new UserProfile();
userProfile.setId(userId); userProfile.setId(userId);

View File

@ -8,6 +8,7 @@ import static org.mockito.Mockito.when;
import com.red.circle.framework.core.dto.ReqSysOrigin; import com.red.circle.framework.core.dto.ReqSysOrigin;
import com.red.circle.other.app.dto.clientobject.user.relation.cp.CpRightsConfigCO; import com.red.circle.other.app.dto.clientobject.user.relation.cp.CpRightsConfigCO;
import com.red.circle.other.app.dto.cmd.user.relation.cp.CpRightsConfigQueryCmd; import com.red.circle.other.app.dto.cmd.user.relation.cp.CpRightsConfigQueryCmd;
import com.red.circle.other.infra.database.cache.service.other.EnumConfigCacheService;
import com.red.circle.other.infra.database.rds.entity.user.user.CpCabinConfig; import com.red.circle.other.infra.database.rds.entity.user.user.CpCabinConfig;
import com.red.circle.other.infra.database.rds.entity.user.user.CpRelationship; 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.CpValue;
@ -54,8 +55,9 @@ class UserCpRightsConfigQueryExeTest {
private final CpCabinConfigService cpCabinConfigService = mock(CpCabinConfigService.class); private final CpCabinConfigService cpCabinConfigService = mock(CpCabinConfigService.class);
private final CpRelationshipService cpRelationshipService = mock(CpRelationshipService.class); private final CpRelationshipService cpRelationshipService = mock(CpRelationshipService.class);
private final CpValueService cpValueService = mock(CpValueService.class); private final CpValueService cpValueService = mock(CpValueService.class);
private final EnumConfigCacheService enumConfigCacheService = mock(EnumConfigCacheService.class);
private final UserCpRightsConfigQueryExe exe = new UserCpRightsConfigQueryExe( private final UserCpRightsConfigQueryExe exe = new UserCpRightsConfigQueryExe(
cpCabinConfigService, cpRelationshipService, cpValueService); cpCabinConfigService, cpRelationshipService, cpValueService, enumConfigCacheService);
private Fixture() { private Fixture() {
for (String relationType : List.of("CP", "BROTHER", "SISTERS")) { for (String relationType : List.of("CP", "BROTHER", "SISTERS")) {

View File

@ -22,7 +22,6 @@ import com.red.circle.other.domain.model.user.UserProfile;
import com.red.circle.other.infra.database.rds.entity.user.user.CpApply; 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.CpApplyService;
import com.red.circle.other.infra.enums.user.user.CpApplyStatus; import com.red.circle.other.infra.enums.user.user.CpApplyStatus;
import com.red.circle.wallet.inner.endpoint.wallet.WalletGoldClient;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -36,7 +35,6 @@ class CpApplyListenerTest {
CpApplyService cpApplyService = mock(CpApplyService.class); CpApplyService cpApplyService = mock(CpApplyService.class);
ImMessageClient imMessageClient = mock(ImMessageClient.class); ImMessageClient imMessageClient = mock(ImMessageClient.class);
UserProfileGateway userProfileGateway = mock(UserProfileGateway.class); UserProfileGateway userProfileGateway = mock(UserProfileGateway.class);
WalletGoldClient walletGoldClient = mock(WalletGoldClient.class);
MessageEventProcess messageEventProcess = mock(MessageEventProcess.class); MessageEventProcess messageEventProcess = mock(MessageEventProcess.class);
CpApply apply = new CpApply() CpApply apply = new CpApply()
.setId(3001L) .setId(3001L)
@ -46,7 +44,7 @@ class CpApplyListenerTest {
.setStatus(CpApplyStatus.WAIT.name()); .setStatus(CpApplyStatus.WAIT.name());
when(cpApplyService.getById(3001L)).thenReturn(apply); when(cpApplyService.getById(3001L)).thenReturn(apply);
when(cpApplyService.changeStatusById(3001L, CpApplyStatus.REIMBURSE)).thenReturn(true); when(cpApplyService.changeStatusById(3001L, CpApplyStatus.EXPIRE)).thenReturn(true);
when(userProfileGateway.getByUserId(1001L)).thenReturn(profile(1001L)); when(userProfileGateway.getByUserId(1001L)).thenReturn(profile(1001L));
when(userProfileGateway.getByUserId(2001L)).thenReturn(profile(2001L)); when(userProfileGateway.getByUserId(2001L)).thenReturn(profile(2001L));
when(imMessageClient.sendCustomMessage(any(CustomC2cMsgBodyCmd.class))) when(imMessageClient.sendCustomMessage(any(CustomC2cMsgBodyCmd.class)))
@ -62,7 +60,7 @@ class CpApplyListenerTest {
}); });
CpApplyListener listener = new CpApplyListener(cpApplyService, imMessageClient, CpApplyListener listener = new CpApplyListener(cpApplyService, imMessageClient,
userProfileGateway, walletGoldClient, messageEventProcess); userProfileGateway, messageEventProcess);
assertEquals(Action.SUCCESS, listener.consume(new ConsumerMessage())); assertEquals(Action.SUCCESS, listener.consume(new ConsumerMessage()));
@ -72,6 +70,7 @@ class CpApplyListenerTest {
List<CustomC2cMsgBodyCmd> messages = captor.getAllValues(); List<CustomC2cMsgBodyCmd> messages = captor.getAllValues();
assertExpiredMessage(messages.get(0), "1001", "2001"); assertExpiredMessage(messages.get(0), "1001", "2001");
assertExpiredMessage(messages.get(1), "2001", "1001"); assertExpiredMessage(messages.get(1), "2001", "1001");
verify(cpApplyService).changeStatusById(3001L, CpApplyStatus.EXPIRE);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -95,6 +95,17 @@ public interface CpApplyService extends BaseService<CpApply> {
*/ */
List<Long> refuseOtherWaitBetweenUsers(Long excludeApplyId, Long userId, Long cpUserId); List<Long> refuseOtherWaitBetweenUsers(Long excludeApplyId, Long userId, Long cpUserId);
/**
* 拒绝两个用户之间除指定申请外的其他等待申请并返回被拒绝的申请记录.
*/
List<CpApply> refuseOtherWaitAppliesBetweenUsers(Long excludeApplyId, Long userId, Long cpUserId);
/**
* 拒绝指定用户所有同类型等待申请并返回被拒绝的申请记录.
*/
List<CpApply> refuseWaitAppliesByUserAndRelation(Long excludeApplyId, Long userId,
String relationType);
/** /**
* 获取两个用户之间已拒绝的申请. * 获取两个用户之间已拒绝的申请.
*/ */

View File

@ -119,8 +119,17 @@ public class CpApplyServiceImpl extends BaseServiceImpl<CpApplyDAO, CpApply> imp
@Override @Override
public List<Long> refuseOtherWaitBetweenUsers(Long excludeApplyId, Long userId, Long cpUserId) { public List<Long> refuseOtherWaitBetweenUsers(Long excludeApplyId, Long userId, Long cpUserId) {
List<Long> applyIds = query() return refuseOtherWaitAppliesBetweenUsers(excludeApplyId, userId, cpUserId)
.select(CpApply::getId) .stream()
.map(CpApply::getId)
.filter(Objects::nonNull)
.toList();
}
@Override
public List<CpApply> refuseOtherWaitAppliesBetweenUsers(Long excludeApplyId, Long userId,
Long cpUserId) {
List<CpApply> applies = query()
.eq(CpApply::getStatus, CpApplyStatus.WAIT) .eq(CpApply::getStatus, CpApplyStatus.WAIT)
.ne(Objects.nonNull(excludeApplyId), CpApply::getId, excludeApplyId) .ne(Objects.nonNull(excludeApplyId), CpApply::getId, excludeApplyId)
.and(where -> where .and(where -> where
@ -129,20 +138,48 @@ public class CpApplyServiceImpl extends BaseServiceImpl<CpApplyDAO, CpApply> imp
.or() .or()
.nested(w -> w.eq(CpApply::getSendApplyUserId, cpUserId) .nested(w -> w.eq(CpApply::getSendApplyUserId, cpUserId)
.eq(CpApply::getAcceptApplyUserId, userId))) .eq(CpApply::getAcceptApplyUserId, userId)))
.list() .list();
.stream() List<Long> applyIds = applies.stream()
.map(CpApply::getId) .map(CpApply::getId)
.filter(Objects::nonNull) .filter(Objects::nonNull)
.toList(); .toList();
if (applyIds.isEmpty()) { if (applyIds.isEmpty()) {
return applyIds; return applies;
} }
update() update()
.set(CpApply::getStatus, CpApplyStatus.REFUSE) .set(CpApply::getStatus, CpApplyStatus.REFUSE)
.set(CpApply::getUpdateTime, LocalDateTime.now()) .set(CpApply::getUpdateTime, LocalDateTime.now())
.in(CpApply::getId, applyIds) .in(CpApply::getId, applyIds)
.execute(); .execute();
return applyIds; applies.forEach(apply -> apply.setStatus(CpApplyStatus.REFUSE.name()));
return applies;
}
@Override
public List<CpApply> refuseWaitAppliesByUserAndRelation(Long excludeApplyId, Long userId,
String relationType) {
List<CpApply> applies = query()
.eq(CpApply::getStatus, CpApplyStatus.WAIT)
.eq(CpApply::getRelationType, CpRelationshipType.normalize(relationType))
.ne(Objects.nonNull(excludeApplyId), CpApply::getId, excludeApplyId)
.and(where -> where.eq(CpApply::getSendApplyUserId, userId)
.or()
.eq(CpApply::getAcceptApplyUserId, userId))
.list();
List<Long> applyIds = applies.stream()
.map(CpApply::getId)
.filter(Objects::nonNull)
.toList();
if (applyIds.isEmpty()) {
return applies;
}
update()
.set(CpApply::getStatus, CpApplyStatus.REFUSE)
.set(CpApply::getUpdateTime, LocalDateTime.now())
.in(CpApply::getId, applyIds)
.execute();
applies.forEach(apply -> apply.setStatus(CpApplyStatus.REFUSE.name()));
return applies;
} }
@Override @Override

View File

@ -32,6 +32,11 @@ public enum CpApplyStatus {
*/ */
REIMBURSE, REIMBURSE,
/**
* 已过期.
*/
EXPIRE,
/** /**
* 分手中. * 分手中.
*/ */