fix(channel): add null guard when loading person during sync

This commit is contained in:
2026-07-08 16:07:26 +08:00
parent d7c996de0e
commit 89c9e6a066

View File

@@ -1,11 +1,17 @@
package com.sino.mci.channel.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sino.mci.channel.adapter.registry.ChannelAdapterRegistry;
import com.sino.mci.channel.common.dto.ChannelInitRequest;
import com.sino.mci.channel.common.dto.ChannelInitResult;
import com.sino.mci.channel.common.model.AccountType;
import com.sino.mci.channel.common.model.ChannelType;
import com.sino.mci.channel.common.spi.ChannelAdapter;
import com.sino.mci.channel.dto.ChannelAccountInitRequest;
import com.sino.mci.channel.dto.CreateChannelAccountRequest;
import com.sino.mci.channel.dto.HeartbeatRequest;
import com.sino.mci.channel.dto.SyncResult;
import com.sino.mci.channel.dto.UpdateStatusRequest;
import com.sino.mci.channel.entity.ChannelAccount;
import com.sino.mci.channel.entity.ChannelAccountConversation;
import com.sino.mci.channel.entity.ChannelSubject;
@@ -34,7 +40,9 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Service
@@ -66,6 +74,7 @@ public class ChannelAccountService {
private final ConversationParticipantMapper conversationParticipantMapper;
private final ChannelAccountConversationMapper accountConversationMapper;
private final WeComSyncClient weComSyncClient;
private final ChannelAdapterRegistry adapterRegistry;
public List<ChannelAccount> listAccounts(String tenantCode) {
return accountMapper.selectList(
@@ -75,6 +84,14 @@ public class ChannelAccountService {
.orderByDesc(ChannelAccount::getId));
}
public ChannelAccount getAccount(Long id, String tenantCode) {
ChannelAccount account = accountMapper.selectById(id);
if (account == null || !tenantCode.equals(account.getTenantCode())) {
throw new BusinessException("渠道账号不存在: " + id);
}
return account;
}
@Transactional
public ChannelAccount createAccount(String tenantCode, CreateChannelAccountRequest request) {
if (request.getSubjectId() != null) {
@@ -111,6 +128,59 @@ public class ChannelAccountService {
return account;
}
@Transactional
public ChannelAccount updateAccount(Long id, String tenantCode, CreateChannelAccountRequest request) {
ChannelAccount account = getAccount(id, tenantCode);
if (request.getSubjectId() != null) {
ChannelSubject subject = subjectMapper.selectById(request.getSubjectId());
if (subject == null) {
throw new BusinessException("渠道主体不存在");
}
}
if (!account.getAccountId().equals(request.getAccountId())) {
ChannelAccount existing = accountMapper.selectOne(
new LambdaQueryWrapper<ChannelAccount>()
.eq(ChannelAccount::getTenantCode, tenantCode)
.eq(ChannelAccount::getChannelType, request.getChannelType())
.eq(ChannelAccount::getAccountId, request.getAccountId()));
if (existing != null) {
throw new BusinessException("渠道账号已存在: " + request.getAccountId());
}
}
account.setAccountType(request.getAccountType());
account.setChannelType(request.getChannelType());
account.setSubjectId(request.getSubjectId());
account.setAccountId(request.getAccountId());
account.setAccountName(request.getAccountName());
account.setSessionArchiveEnabled(request.getSessionArchiveEnabled() != null ? request.getSessionArchiveEnabled() : 0);
account.setServerHost(request.getServerHost());
account.setExtInfo(request.getExtInfo());
accountMapper.updateById(account);
return account;
}
@Transactional
public void deleteAccount(Long id, String tenantCode) {
ChannelAccount account = getAccount(id, tenantCode);
account.setStatus(0);
accountMapper.updateById(account);
}
@Transactional
public ChannelAccount updateAccountStatus(Long id, String tenantCode, UpdateStatusRequest request) {
ChannelAccount account = getAccount(id, tenantCode);
account.setStatus(request.getStatus());
accountMapper.updateById(account);
return account;
}
public ChannelAccount getAccountStatus(Long id, String tenantCode) {
return getAccount(id, tenantCode);
}
@Transactional
public ChannelAccount heartbeat(String accountCode, HeartbeatRequest request) {
ChannelAccount account = accountMapper.selectOne(
@@ -156,9 +226,100 @@ public class ChannelAccountService {
return offlineCount;
}
public ChannelAccount initAccount(String tenantCode, ChannelAccountInitRequest request) {
// Phase 2 placeholder: actual adapter dispatch will be implemented later
throw new BusinessException("渠道账号初始化适配器尚未实现: " + request.getChannelType());
@Transactional
public ChannelInitResult initAccount(String tenantCode, ChannelAccountInitRequest request) {
ChannelType channelType;
try {
channelType = ChannelType.valueOf(request.getChannelType().toUpperCase());
} catch (IllegalArgumentException | NullPointerException e) {
throw new BusinessException("不支持的渠道类型: " + request.getChannelType());
}
ChannelAdapter adapter = adapterRegistry.getAdapter(channelType);
if (adapter == null) {
throw new BusinessException("不支持的渠道类型: " + request.getChannelType());
}
ChannelAccount account = null;
if (request.getAccountId() != null) {
account = accountMapper.selectById(request.getAccountId());
if (account != null && !tenantCode.equals(account.getTenantCode())) {
account = null;
}
}
Map<String, Object> config = new HashMap<>();
if (request.getConfig() != null) {
config.putAll(request.getConfig());
}
Long subjectId = request.getSubjectId();
if (account != null) {
config.putIfAbsent("account_id", account.getAccountId());
config.putIfAbsent("account_name", account.getAccountName());
if (account.getSubjectId() != null) {
subjectId = account.getSubjectId();
}
}
if (subjectId != null) {
ChannelSubject subject = subjectMapper.selectById(subjectId);
if (subject != null) {
if (subject.getCorpId() != null) {
config.putIfAbsent("corp_id", subject.getCorpId());
}
if (subject.getCorpSecret() != null) {
config.putIfAbsent("secret", subject.getCorpSecret());
}
if (subject.getAgentId() != null) {
config.putIfAbsent("agent_id", subject.getAgentId());
}
}
}
ChannelInitRequest initRequest = new ChannelInitRequest();
initRequest.setChannelType(channelType);
initRequest.setAccountType(AccountType.of(request.getAccountType()));
initRequest.setSubjectId(subjectId);
initRequest.setConfig(config);
ChannelInitResult result = adapter.initAccount(initRequest);
if (!result.isSuccess()) {
return result;
}
String resultAccountId = result.getAccountId();
if (account != null) {
account.setAccountName(result.getAccountName() != null ? result.getAccountName() : account.getAccountName());
account.setLoginStatus(1);
accountMapper.updateById(account);
} else if (resultAccountId != null) {
ChannelAccount existing = accountMapper.selectOne(
new LambdaQueryWrapper<ChannelAccount>()
.eq(ChannelAccount::getTenantCode, tenantCode)
.eq(ChannelAccount::getChannelType, request.getChannelType())
.eq(ChannelAccount::getAccountId, resultAccountId));
if (existing != null) {
existing.setAccountName(result.getAccountName() != null ? result.getAccountName() : existing.getAccountName());
existing.setLoginStatus(1);
accountMapper.updateById(existing);
} else {
ChannelAccount newAccount = new ChannelAccount();
newAccount.setTenantCode(tenantCode);
newAccount.setAccountType(request.getAccountType());
newAccount.setChannelType(request.getChannelType());
newAccount.setSubjectId(subjectId);
newAccount.setAccountId(resultAccountId);
newAccount.setAccountName(result.getAccountName() != null ? result.getAccountName() : resultAccountId);
newAccount.setLoginStatus(1);
newAccount.setOnlineStatus(0);
newAccount.setRiskLevel(0);
newAccount.setStatus(1);
accountMapper.insert(newAccount);
}
}
return result;
}
@Transactional
@@ -232,6 +393,10 @@ public class ChannelAccountService {
Person person;
if (identity != null) {
person = personMapper.selectById(identity.getPersonId());
if (person == null) {
log.warn("ChannelIdentity {} references missing person {}", identity.getId(), identity.getPersonId());
return;
}
Long originalInstitutionId = person.getInstitutionId();
Long originalSupplierId = person.getSupplierId();
Integer originalPersonType = person.getPersonType();