fix(channel): add null guard when loading person during sync
This commit is contained in:
@@ -1,11 +1,17 @@
|
|||||||
package com.sino.mci.channel.service;
|
package com.sino.mci.channel.service;
|
||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
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.model.ChannelType;
|
||||||
|
import com.sino.mci.channel.common.spi.ChannelAdapter;
|
||||||
import com.sino.mci.channel.dto.ChannelAccountInitRequest;
|
import com.sino.mci.channel.dto.ChannelAccountInitRequest;
|
||||||
import com.sino.mci.channel.dto.CreateChannelAccountRequest;
|
import com.sino.mci.channel.dto.CreateChannelAccountRequest;
|
||||||
import com.sino.mci.channel.dto.HeartbeatRequest;
|
import com.sino.mci.channel.dto.HeartbeatRequest;
|
||||||
import com.sino.mci.channel.dto.SyncResult;
|
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.ChannelAccount;
|
||||||
import com.sino.mci.channel.entity.ChannelAccountConversation;
|
import com.sino.mci.channel.entity.ChannelAccountConversation;
|
||||||
import com.sino.mci.channel.entity.ChannelSubject;
|
import com.sino.mci.channel.entity.ChannelSubject;
|
||||||
@@ -34,7 +40,9 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Service
|
@Service
|
||||||
@@ -66,6 +74,7 @@ public class ChannelAccountService {
|
|||||||
private final ConversationParticipantMapper conversationParticipantMapper;
|
private final ConversationParticipantMapper conversationParticipantMapper;
|
||||||
private final ChannelAccountConversationMapper accountConversationMapper;
|
private final ChannelAccountConversationMapper accountConversationMapper;
|
||||||
private final WeComSyncClient weComSyncClient;
|
private final WeComSyncClient weComSyncClient;
|
||||||
|
private final ChannelAdapterRegistry adapterRegistry;
|
||||||
|
|
||||||
public List<ChannelAccount> listAccounts(String tenantCode) {
|
public List<ChannelAccount> listAccounts(String tenantCode) {
|
||||||
return accountMapper.selectList(
|
return accountMapper.selectList(
|
||||||
@@ -75,6 +84,14 @@ public class ChannelAccountService {
|
|||||||
.orderByDesc(ChannelAccount::getId));
|
.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
|
@Transactional
|
||||||
public ChannelAccount createAccount(String tenantCode, CreateChannelAccountRequest request) {
|
public ChannelAccount createAccount(String tenantCode, CreateChannelAccountRequest request) {
|
||||||
if (request.getSubjectId() != null) {
|
if (request.getSubjectId() != null) {
|
||||||
@@ -111,6 +128,59 @@ public class ChannelAccountService {
|
|||||||
return account;
|
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
|
@Transactional
|
||||||
public ChannelAccount heartbeat(String accountCode, HeartbeatRequest request) {
|
public ChannelAccount heartbeat(String accountCode, HeartbeatRequest request) {
|
||||||
ChannelAccount account = accountMapper.selectOne(
|
ChannelAccount account = accountMapper.selectOne(
|
||||||
@@ -156,9 +226,100 @@ public class ChannelAccountService {
|
|||||||
return offlineCount;
|
return offlineCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChannelAccount initAccount(String tenantCode, ChannelAccountInitRequest request) {
|
@Transactional
|
||||||
// Phase 2 placeholder: actual adapter dispatch will be implemented later
|
public ChannelInitResult initAccount(String tenantCode, ChannelAccountInitRequest request) {
|
||||||
throw new BusinessException("渠道账号初始化适配器尚未实现: " + request.getChannelType());
|
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
|
@Transactional
|
||||||
@@ -232,6 +393,10 @@ public class ChannelAccountService {
|
|||||||
Person person;
|
Person person;
|
||||||
if (identity != null) {
|
if (identity != null) {
|
||||||
person = personMapper.selectById(identity.getPersonId());
|
person = personMapper.selectById(identity.getPersonId());
|
||||||
|
if (person == null) {
|
||||||
|
log.warn("ChannelIdentity {} references missing person {}", identity.getId(), identity.getPersonId());
|
||||||
|
return;
|
||||||
|
}
|
||||||
Long originalInstitutionId = person.getInstitutionId();
|
Long originalInstitutionId = person.getInstitutionId();
|
||||||
Long originalSupplierId = person.getSupplierId();
|
Long originalSupplierId = person.getSupplierId();
|
||||||
Integer originalPersonType = person.getPersonType();
|
Integer originalPersonType = person.getPersonType();
|
||||||
|
|||||||
Reference in New Issue
Block a user