REQ-3581: 很多东西

This commit is contained in:
yanglin 2025-02-24 17:15:28 +08:00
parent 63eefa1ce3
commit 607347f001
19 changed files with 299 additions and 151 deletions

View File

@ -13,7 +13,8 @@ import java.util.Arrays;
@Getter
public enum MQEvent {
ESS_CONTRACT_STATE_CHANGE("nanopart", "ess-contract-state-change", "腾讯电子签合同状态变化")
ESS_CONTRACT_STATE_CHANGE("nanopart", "ess-contract-state-change", "腾讯电子签合同状态变化"),
ESS_CONTRACT_DOWNLOAD_PDF("nanopart", "ess-contract-download-pdf", "腾讯电子签合同下载PDF"),
;
private final String model;

View File

@ -0,0 +1,24 @@
package cn.axzo.nanopart.ess.api.mq;
import cn.axzo.nanopart.ess.api.domain.contract.EssContractInfo;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class EssContractDownloadPDFEvent extends MqMessage {
/**
* 合同信息
*/
private EssContractInfo contract;
/**
* 是否重复下载
*/
private boolean retryDownload;
}

View File

@ -18,6 +18,11 @@ public class SaveContractSnapshotRequest {
@NotBlank(message = "essContractId不能为空")
private String essContractId;
/**
* 是否重复下载, 即已经下载过了, 但是需要重新下载
*/
private boolean retryDownload = false;
@Override
public String toString() {
return JSON.toJSONString(this);

View File

@ -9,7 +9,6 @@ import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.Getter;
import lombok.Setter;
import java.util.HashSet;
import java.util.Set;
/**
@ -57,20 +56,10 @@ public class EssOrg extends BaseEntity<EssOrg> {
return recordExt;
}
public boolean isPotentialSuperAdmin(Long personId) {
if (superAdminPersonId != null && superAdminPersonId.equals(personId))
return true;
return getOrCreateExt().isPotentialSuperAdmin(personId);
}
public boolean isAuthorized() {
return isAuthorized.isYes();
}
public boolean isCreateBy(Long personId) {
return personId.equals(createByPersonId);
}
@Override
public String toString() {
return JSON.toJSONString(this);
@ -81,12 +70,6 @@ public class EssOrg extends BaseEntity<EssOrg> {
private Set<Long> historySuperAdmins;
public void addHistorySuperAdmin(Long personId) {
if (historySuperAdmins == null)
historySuperAdmins = new HashSet<>();
historySuperAdmins.add(personId);
}
public boolean isPotentialSuperAdmin(Long personId) {
return historySuperAdmins != null && historySuperAdmins.contains(personId);
}

View File

@ -34,7 +34,7 @@ public class EssPerson extends BaseEntity<EssPerson> implements OrgPerson {
private String personName;
/**
* 是否已经认证. YES: 已认证, NO: 未认证
* 是否已经认证
*/
private EssPersonState state;

View File

@ -1,7 +1,6 @@
package cn.axzo.nanopart.ess.server.ess;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
import cn.axzo.nanopart.ess.api.domain.contract.EssApproveDetail;
import cn.axzo.nanopart.ess.api.enums.EssContractState;
import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest;
@ -12,8 +11,10 @@ import cn.axzo.nanopart.ess.server.dao.EssLogDao;
import cn.axzo.nanopart.ess.server.entity.EssContract;
import cn.axzo.nanopart.ess.server.entity.EssPerson;
import cn.axzo.nanopart.ess.server.ess.domain.JsonObjectAsString;
import cn.axzo.nanopart.ess.server.ess.mq.EssBroadcaster;
import cn.axzo.nanopart.ess.server.ess.support.ContractSupport;
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
import cn.axzo.nanopart.ess.server.utils.BizTransactional;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.essbasic.v20210526.models.ApproverItem;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowByFilesResponse;
@ -21,7 +22,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
@ -54,18 +54,7 @@ public class ContractManager {
try {
contract = contractSupport.saveContractByFile(request);
} catch (DuplicateKeyException e) {
log.warn("幂等重复, request={}", request, e);
EssContract savedContract = essContractDao
.findByIdempotentCode(request.getAppCode(), request.getIdempotentCode())
.orElseThrow(InternalError::new);
essLogDao.log("createContractByFile", savedContract.getEssContractId(),
"message", "幂等重复", "request", request);
CreateContractByFileResponse response = new CreateContractByFileResponse();
response.setEssContractId(savedContract.getEssContractId());
response.setEssRecipientIds(savedContract.getApprovers().stream()
.map(Approver::getEssRecipientId)
.collect(toList()));
return response;
return contractSupport.createDuplicateContractByFileResponse(request);
}
try {
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(request.getCreator().getOuId());
@ -94,7 +83,7 @@ public class ContractManager {
}
}
@Transactional
@BizTransactional
public void revokeContract(RevokeContractRequest request) {
essLogDao.logRequest("revokeContract", request.getEssContractId(), request);
EssContract contract = essContractDao.getOrThrow(request.getEssContractId());
@ -105,7 +94,7 @@ public class ContractManager {
updateContractState(contract, EssContractState.CANCEL, null, request.getReason());
}
@Transactional
@BizTransactional
public void updateContractState(EssContract contract,
EssContractState state,
List<EssApproveDetail> approveDetails,

View File

@ -10,6 +10,7 @@ import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
import cn.axzo.nanopart.ess.api.request.GetEmbedWebUrlRequest;
import cn.axzo.nanopart.ess.api.request.GetSignUrlRequest;
import cn.axzo.nanopart.ess.api.request.RemoveSealAuthorizationRequest;
import cn.axzo.nanopart.ess.api.request.SaveContractSnapshotRequest;
import cn.axzo.nanopart.ess.api.request.SealAndPersonRequest;
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
import cn.axzo.nanopart.ess.server.dao.EssLogDao;
@ -22,9 +23,10 @@ import cn.axzo.nanopart.ess.server.entity.EssSeal;
import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
import cn.axzo.nanopart.ess.server.ess.domain.OrgAndPerson;
import cn.axzo.nanopart.ess.server.ess.domain.SealAndPerson;
import cn.axzo.nanopart.ess.server.ess.support.EssSupport;
import cn.axzo.nanopart.ess.server.ess.mq.EssBroadcaster;
import cn.axzo.nanopart.ess.server.ess.support.OssService;
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
import cn.axzo.nanopart.ess.server.utils.BizTransactional;
import cn.axzo.nanopart.ess.server.utils.IdBuilder;
import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsResponse;
import com.tencentcloudapi.essbasic.v20210526.models.SignUrlInfo;
@ -32,8 +34,6 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import java.util.function.Function;
@ -54,10 +54,9 @@ public class EssService {
private final EssPersonDao essPersonDao;
private final OssService ossService;
private final EssLogDao essLogDao;
private final EssSupport essSupport;
private final TransactionTemplate transactionTemplate;
private final EssBroadcaster essBroadcaster;
@Transactional
@BizTransactional
public String createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) {
String subject = IdBuilder.builder()
.append(request.getOuId())
@ -86,7 +85,7 @@ public class EssService {
contextPerson, request.getEmbedType(), request.getBusinessId());
}
@Transactional
@BizTransactional
public void essAddSealAuthorization(AddSealAuthorizationRequest request) {
String subject = IdBuilder.builder()
.append(request.getEssSealId())
@ -105,7 +104,7 @@ public class EssService {
orgManager.addSealAuthorization(request.getEssSealId(), request.getPersonId(), request.getOperatorPersonId());
}
@Transactional
@BizTransactional
public void essRemoveSealAuthorization(RemoveSealAuthorizationRequest request) {
String subject = IdBuilder.builder()
.append(request.getEssSealId())
@ -174,39 +173,50 @@ public class EssService {
EssContract contract = essContractDao.getOrThrow(essContractId);
if (StringUtils.isNotBlank(contract.getOssFileKey()))
return ossService.getOssUrl(contract.getOssFileKey());
maybeUploadContractToOss(contract);
return getContractPDFUrlFromEss(contract);
}
public void saveContractSnapshot(String essContractId) {
EssContract c = transactionTemplate.execute(unused -> {
EssContract contract = essContractDao.getOrThrow(essContractId);
contract.getOrCreateExt().setShouldDownloadContract(true);
essContractDao.updateExt(contract);
return contract;
});
maybeUploadContractToOss(c);
@BizTransactional
public void saveContractSnapshot(SaveContractSnapshotRequest request) {
essLogDao.logRequest("saveContractSnapshot", request.getEssContractId(), request);
EssContract contract = essContractDao.getOrThrow(request.getEssContractId());
contract.getOrCreateExt().setShouldDownloadContract(true);
essContractDao.updateExt(contract);
maybeScheduleDownloadContractPDF(contract, request.isRetryDownload());
}
public void maybeUploadContractToOss(EssContract contract) {
essSupport.asyncExec(() -> {
EssContract c = essContractDao.findOrNull(contract.getEssContractId());
if (c == null || !c.shouldDownloadContract() || StringUtils.isNotBlank(c.getOssFileKey()))
return;
try {
String pdfUrl = getContractPDFUrlFromEss(c);
String fileName = String.format("%s.pdf", c.getContractName());
String fileKey = ossService.uploadToOss(pdfUrl, fileName);
transactionTemplate.executeWithoutResult(unused -> {
essContractDao.setOssFileKey(c, fileKey);
essLogDao.log("uploadContractToOss", c.getEssContractId(), "ossFileKey", fileKey);
});
log.info("上传合同到OSS成功, essContractId={}", c.getEssContractId());
} catch (Exception e) {
log.warn("上传合同到OSS失败", e);
essLogDao.log(e, "uploadContractToOss", c.getEssContractId());
}
});
public void maybeScheduleDownloadContractPDF(EssContract contract, boolean retryDownload) {
EssContract reload = essContractDao.findOrNull(contract.getEssContractId());
if (shouldDownloadContractPDF(reload))
essBroadcaster.fireDownloadContractPDF(contract, retryDownload);
}
private boolean shouldDownloadContractPDF(EssContract contract) {
return contract != null && contract.shouldDownloadContract();
}
@BizTransactional
public void downloadContractPDF(EssContract contract, boolean retryDownload) {
if (StringUtils.isNotBlank(contract.getOssFileKey()) && !retryDownload) {
log.info("合同已下载PDF, contract={}", contract);
return;
}
if (!shouldDownloadContractPDF(contract)) {
log.info("合同不需要下载PDF, contract={}", contract);
return;
}
try {
String pdfUrl = getContractPDFUrlFromEss(contract);
String fileName = String.format("%s.pdf", contract.getContractName());
String fileKey = ossService.uploadToOss(pdfUrl, fileName);
essContractDao.setOssFileKey(contract, fileKey);
essLogDao.log("uploadContractToOss", contract.getEssContractId(),
"ossFileKey", fileKey, "forceDownload", retryDownload);
log.info("上传合同到OSS成功, essContractId={}", contract.getEssContractId());
} catch (Exception e) {
log.warn("上传合同到OSS失败", e);
essLogDao.log(e, "uploadContractToOss", contract.getEssContractId());
}
}
private String getContractPDFUrlFromEss(EssContract contract) {

View File

@ -19,13 +19,13 @@ import cn.axzo.nanopart.ess.server.ess.domain.OrgAndPerson;
import cn.axzo.nanopart.ess.server.ess.domain.SealPersons;
import cn.axzo.nanopart.ess.server.ess.support.EssSupport;
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
import cn.axzo.nanopart.ess.server.utils.BizTransactional;
import com.google.common.collect.Sets;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
@ -49,7 +49,7 @@ public class OrgManager {
// !! login
@Transactional
@BizTransactional
public OrgAndPerson createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) {
EssOrg org = essOrgDao.findForUpdateOrNull(request.getOuId());
if (org == null) {
@ -62,7 +62,7 @@ public class OrgManager {
// !! org and person
@Transactional
@BizTransactional
public void addAuthorizedOrgPerson(OrgPerson orgPerson) {
EssPerson person = getOrCreateOrgPerson(orgPerson);
essPersonDao.setState(person, EssPersonState.AUTHORIZED);
@ -80,24 +80,14 @@ public class OrgManager {
return essPerson;
}
@Transactional
@BizTransactional
public void setOrgAuthorized(Long ouId, Long superAdmin) {
essOrgDao.setOrgAuthorized(ouId, superAdmin);
addSuperAdmin(ouId, superAdmin);
}
@Transactional
@BizTransactional
public void changeSuperAdmin(Long ouId, Long superAdmin) {
essOrgDao.changeSuperAdmin(ouId, superAdmin);
addSuperAdmin(ouId, superAdmin);
}
@Transactional
public void addSuperAdmin(Long ouId, Long superAdmin) {
EssOrg org = essOrgDao.findForUpdateOrNull(ouId);
if (org == null) return;
org.getOrCreateExt().addHistorySuperAdmin(superAdmin);
essOrgDao.updateExt(org);
}
public EssPerson getSuperAdminOrThrow(Long ouId) {
@ -116,7 +106,7 @@ public class OrgManager {
// !! seal
@Transactional
@BizTransactional
public boolean maybeAddSeal(Long ouId, String essSealId, EssSealType type) {
EssSeal seal = essSealDao.findByEssSealId(essSealId).orElse(null);
if (seal != null)
@ -138,19 +128,19 @@ public class OrgManager {
essSealDao.updateState(essSealId, state);
}
@Transactional
@BizTransactional
public void addSealAuthorization(String essSealId, Long personId, Long authorizedByPersonId) {
maybeAddSealPersons(essSealId, Sets.newHashSet(personId));
essSealPersonDao.setPersonAuthorized(essSealId, personId, authorizedByPersonId);
}
@Transactional
@BizTransactional
public void removeSealAuthorization(String essSealId, Long personId) {
maybeAddSealPersons(essSealId, Sets.newHashSet(personId));
essSealPersonDao.removeSealAuthorization(essSealId, personId);
}
@Transactional
@BizTransactional
public void maybeAddSealPersons(String essSealId, Set<Long> personIds) {
EssSeal seal = essSealDao.findByEssSealId(essSealId).orElse(null);
BizAssertions.assertNotNull(seal, "印章不存在: {}", essSealId);
@ -176,7 +166,7 @@ public class OrgManager {
}
}
@Transactional
@BizTransactional
public void tryRemoveSealPerson(RemoveSealPersonRequest request) {
EssSeal seal = essSealDao.findByEssSealId(request.getEssSealId()).orElse(null);
BizAssertions.assertNotNull(seal, "印章不存在: {}", request.getEssSealId());

View File

@ -141,7 +141,7 @@ class ApiController implements EssApi {
@Override
public ApiResult<Void> saveContractSnapshot(SaveContractSnapshotRequest request) {
log.info("saveContractSnapshot request={}", request);
essService.saveContractSnapshot(request.getEssContractId());
essService.saveContractSnapshot(request);
return ApiResult.ok();
}

View File

@ -160,7 +160,7 @@ class CallbackController implements EssCallbackApi, InitializingBean {
log.warn("contract not found: {}", changes.getFlowId());
} else {
contractManager.updateContractState(contract, state, approveDetails, changes.getFlowMessage());
essService.maybeUploadContractToOss(contract);
essService.maybeScheduleDownloadContractPDF(contract, false);
}
return changes.getFlowId();
});

View File

@ -0,0 +1,48 @@
package cn.axzo.nanopart.ess.server.ess.mq;
import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventConsumer;
import cn.axzo.framework.rocketmq.EventHandler;
import cn.axzo.nanopart.ess.api.enums.MQEvent;
import cn.axzo.nanopart.ess.api.mq.EssContractDownloadPDFEvent;
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
import cn.axzo.nanopart.ess.server.entity.EssContract;
import cn.axzo.nanopart.ess.server.ess.EssService;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import java.util.Collections;
/**
* @author yanglin
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class DownloadContractHandler implements EventHandler, InitializingBean {
private final EventConsumer eventConsumer;
private final EssContractDao essContractDao;
private final EssService essService;
@Override
public void onEvent(Event event, EventConsumer.Context context) {
EssContractDownloadPDFEvent message = event.normalizedData(EssContractDownloadPDFEvent.class);
log.info("receive download contract pdf event: {}", JSON.toJSONString(message));
EssContract contract = essContractDao.findOrNull(message.getContract().getEssContractId());
if (contract == null)
log.info("try download contract pdf but contract not found: {}", JSON.toJSONString(message));
else
essService.downloadContractPDF(contract, message.isRetryDownload());
}
@Override
public void afterPropertiesSet() {
eventConsumer.registerHandlers(Collections.singletonList(
MQEvent.ESS_CONTRACT_DOWNLOAD_PDF.getEventCode()), this);
}
}

View File

@ -1,10 +1,11 @@
package cn.axzo.nanopart.ess.server.ess;
package cn.axzo.nanopart.ess.server.ess.mq;
import cn.axzo.basics.common.BeanMapper;
import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventProducer;
import cn.axzo.nanopart.ess.api.domain.contract.EssContractInfo;
import cn.axzo.nanopart.ess.api.enums.MQEvent;
import cn.axzo.nanopart.ess.api.mq.EssContractDownloadPDFEvent;
import cn.axzo.nanopart.ess.api.mq.EssContractStateChangeMessage;
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
import cn.axzo.nanopart.ess.server.entity.EssContract;
@ -16,12 +17,12 @@ import org.springframework.stereotype.Component;
*/
@Component
@RequiredArgsConstructor
class EssBroadcaster {
public class EssBroadcaster {
private final EssContractDao essContractDao;
protected final EventProducer<?> eventProducer;
void fireContractStateChanged(EssContract contract) {
public void fireContractStateChanged(EssContract contract) {
EssContract reloadContract = essContractDao.findOrNull(contract.getEssContractId());
if (reloadContract == null)
return;
@ -36,4 +37,17 @@ class EssBroadcaster {
.build());
}
public void fireDownloadContractPDF(EssContract contract, boolean forceDownload) {
EssContractDownloadPDFEvent message = new EssContractDownloadPDFEvent();
message.setContract(BeanMapper.copyBean(contract, EssContractInfo.class));
message.setRetryDownload(forceDownload);
eventProducer.send(Event.builder()
.eventCode(MQEvent.ESS_CONTRACT_DOWNLOAD_PDF.getEventCode())
.shardingKey(contract.getEssContractId())
.targetId(contract.getEssContractId())
.targetType("ess-contract")
.data(message)
.build());
}
}

View File

@ -1,23 +1,19 @@
package cn.axzo.nanopart.ess.server.ess;
package cn.axzo.nanopart.ess.server.ess.mq;
import cn.axzo.framework.rocketmq.BaseListener;
import cn.axzo.framework.rocketmq.Event;
import cn.axzo.framework.rocketmq.EventConsumer;
import cn.axzo.framework.rocketmq.EventHandler;
import cn.axzo.maokai.api.domain.event.user.OrgUserStatusChangedEvent;
import cn.axzo.nanopart.ess.server.dao.EssLogDao;
import cn.axzo.nanopart.ess.server.dao.EssOrgDao;
import cn.axzo.nanopart.ess.server.dao.EssPersonDao;
import cn.axzo.nanopart.ess.server.entity.EssOrg;
import cn.axzo.nanopart.ess.server.entity.EssPerson;
import cn.axzo.nanopart.ess.server.ess.EssClient;
import cn.axzo.nanopart.ess.server.ess.OrgManager;
import cn.axzo.nanopart.ess.server.utils.IdBuilder;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
@ -30,55 +26,51 @@ import java.util.Collections;
@Slf4j
@Component
@RequiredArgsConstructor
@RocketMQMessageListener(
maxReconsumeTimes = 3,
consumeMode = ConsumeMode.ORDERLY,
nameServer = "${rocketmq.name-server}",
topic = "topic_organizational_${spring.profiles.active}",
consumerGroup = "GID_ess_person_resign_${spring.application.name}_${spring.profiles.active}"
)
public class PersonResignListener extends BaseListener
implements RocketMQListener<MessageExt>, EventHandler, InitializingBean {
public class PersonResignHandler implements EventHandler, InitializingBean {
private final EventConsumer eventConsumer;
private final EssClient essClient;
private final OrgManager orgManager;
private final EssOrgDao essOrgDao;
private final EssPersonDao essPersonDao;
private final EssLogDao essLogDao;
private final TransactionTemplate transactionTemplate;
@Override
public void onMessage(MessageExt message) {
log.info("receive mq message: {}", JSON.toJSONString(message));
super.onEvent(message, eventConsumer);
}
@Override
public void onEvent(Event event, EventConsumer.Context context) {
OrgUserStatusChangedEvent userEvent = event.normalizedData(OrgUserStatusChangedEvent.class);
log.info("receive user event: {}", JSON.toJSONString(userEvent));
if (userEvent.getStatusCode() == 6)
transactionTemplate.executeWithoutResult(unused -> trySetPersonResigned(userEvent));
OrgUserStatusChangedEvent message = event.normalizedData(OrgUserStatusChangedEvent.class);
log.info("receive node user event: {}", JSON.toJSONString(message));
if (message.getStatusCode() == 6)
transactionTemplate.executeWithoutResult(unused -> trySetPersonResigned(message));
else
log.info("ignore user event: {}", JSON.toJSONString(userEvent));
log.info("ignore node user event: {}", JSON.toJSONString(message));
}
private void trySetPersonResigned(OrgUserStatusChangedEvent event) {
EssOrg org = essOrgDao.findOrNull(event.getOuId());
if (org == null) return;
if (org == null) {
log.info("未找到单位: {}", JSON.toJSONString(event));
return;
}
if (!org.isAuthorized()) {
log.info("ignore unauthorized org: {}", JSON.toJSONString(org));
return;
}
EssPerson person = essPersonDao.findOrNull(event.getOuId(), event.getPersonId());
String subject = IdBuilder.builder()
.append(event.getOuId())
.append(event.getPersonId())
.build();
if (person == null) {
essLogDao.log("personResigned", subject, "event", event, "isAuthorized", false);
log.info("ignore person resigned: {}, personNotFound", JSON.toJSONString(event));
return;
}
if (!person.isAuthorized()) {
log.info("ignore unauthorized person resigned: {}", JSON.toJSONString(person));
return;
}
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(event.getOuId());
boolean isSuperAdmin = org.isPotentialSuperAdmin(event.getPersonId());
essLogDao.log("personResigned", subject, "event", event, "isPotentialSuperAdmin", isSuperAdmin);
boolean isSuperAdmin = superAdmin.getPersonId().equals(event.getPersonId());
log.info("set person resigned: {}, isSuperAdmin: {}", JSON.toJSONString(person), isSuperAdmin);
if (isSuperAdmin) {
log.info("ignore super admin resigned: {}", JSON.toJSONString(person));
return;
@ -93,5 +85,4 @@ public class PersonResignListener extends BaseListener
eventConsumer.registerHandlers(Collections.singletonList(
Event.EventCode.from("org-user:org-user-movement")), this);
}
}

View File

@ -5,13 +5,16 @@ import cn.axzo.nanopart.ess.api.domain.contract.Approver;
import cn.axzo.nanopart.ess.api.enums.Constraint;
import cn.axzo.nanopart.ess.api.enums.EssContractState;
import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest;
import cn.axzo.nanopart.ess.api.response.CreateContractByFileResponse;
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
import cn.axzo.nanopart.ess.server.dao.EssLogDao;
import cn.axzo.nanopart.ess.server.dao.EssOrgDao;
import cn.axzo.nanopart.ess.server.entity.EssContract;
import cn.axzo.nanopart.ess.server.entity.EssOrg;
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Collections;
@ -23,12 +26,14 @@ import static java.util.stream.Collectors.toList;
/**
* @author yanglin
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class ContractSupport {
private final EssOrgDao essOrgDao;
private final EssContractDao essContractDao;
private final EssLogDao essLogDao;
public void validateCreateContract(CreateContractInfo contract) {
checkCreateContractConstraint(contract);
@ -79,4 +84,20 @@ public class ContractSupport {
return contract;
}
public CreateContractByFileResponse
createDuplicateContractByFileResponse(CreateContractByFileRequest request) {
log.warn("幂等重复, request={}", request);
EssContract savedContract = essContractDao
.findByIdempotentCode(request.getAppCode(), request.getIdempotentCode())
.orElseThrow(InternalError::new);
essLogDao.log("createContractByFile", savedContract.getEssContractId(),
"message", "幂等重复", "request", request);
CreateContractByFileResponse response = new CreateContractByFileResponse();
response.setEssContractId(savedContract.getEssContractId());
response.setEssRecipientIds(savedContract.getApprovers().stream()
.map(Approver::getEssRecipientId)
.collect(toList()));
return response;
}
}

View File

@ -13,7 +13,6 @@ import cn.axzo.nanopart.ess.server.entity.EssOrg;
import cn.axzo.nanopart.ess.server.entity.EssPerson;
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
import cn.azxo.framework.common.model.CommonResponse;
import cn.hutool.core.thread.NamedThreadFactory;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
@ -22,11 +21,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
import java.util.concurrent.TimeUnit;
import static cn.axzo.nanopart.ess.server.utils.BizAssertions.assertResponse;
@ -38,12 +32,6 @@ import static cn.axzo.nanopart.ess.server.utils.BizAssertions.assertResponse;
@RequiredArgsConstructor
public class EssSupport {
private final ExecutorService executor = new ThreadPoolExecutor(1, 5,
0L, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(1024),
new NamedThreadFactory(EssSupport.class.getName(), false),
new CallerRunsPolicy());
private final OrganizationalUnitApi organizationalUnitApi;
private final UserProfileServiceApi userProfileServiceApi;
@ -105,8 +93,4 @@ public class EssSupport {
return assertResponse(userProfileServiceApi.getPersonProfiles(personIds));
}
public void asyncExec(Runnable task) {
executor.execute(task);
}
}

View File

@ -5,9 +5,7 @@ import cn.axzo.nanopart.ess.server.utils.BizAssertions;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* @author yanglin
@ -17,10 +15,6 @@ public class PersonProfiles {
private final List<PersonProfileDto> profiles;
public static PersonProfiles empty() {
return new PersonProfiles(Collections.emptyList());
}
public static PersonProfiles wrap(List<PersonProfileDto> profiles) {
return new PersonProfiles(profiles);
}

View File

@ -0,0 +1,38 @@
package cn.axzo.nanopart.ess.server.mq;
import cn.axzo.framework.rocketmq.BaseListener;
import cn.axzo.framework.rocketmq.EventConsumer;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
/**
* @author yanglin
*/
@Slf4j
@Component
@RequiredArgsConstructor
@RocketMQMessageListener(
maxReconsumeTimes = 3,
consumeMode = ConsumeMode.ORDERLY,
nameServer = "${rocketmq.name-server}",
topic = "topic_nanopart_${spring.profiles.active}",
consumerGroup = "ess_download_contract_pdf_${spring.application.name}_${spring.profiles.active}"
)
public class NanopartEssListener extends BaseListener
implements RocketMQListener<MessageExt> {
private final EventConsumer eventConsumer;
@Override
public void onMessage(MessageExt message) {
log.info("receive mq message: {}", JSON.toJSONString(message));
super.onEvent(message, eventConsumer);
}
}

View File

@ -0,0 +1,37 @@
package cn.axzo.nanopart.ess.server.mq;
import cn.axzo.framework.rocketmq.BaseListener;
import cn.axzo.framework.rocketmq.EventConsumer;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.rocketmq.common.message.MessageExt;
import org.apache.rocketmq.spring.annotation.ConsumeMode;
import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
import org.apache.rocketmq.spring.core.RocketMQListener;
import org.springframework.stereotype.Component;
/**
* @author yanglin
*/
@Slf4j
@Component
@RequiredArgsConstructor
@RocketMQMessageListener(
maxReconsumeTimes = 3,
consumeMode = ConsumeMode.ORDERLY,
nameServer = "${rocketmq.name-server}",
topic = "topic_organizational_${spring.profiles.active}",
consumerGroup = "ess_person_resign_${spring.application.name}_${spring.profiles.active}"
)
public class OrganizationalListener extends BaseListener implements RocketMQListener<MessageExt> {
private final EventConsumer eventConsumer;
@Override
public void onMessage(MessageExt message) {
log.info("receive mq message: {}", JSON.toJSONString(message));
super.onEvent(message, eventConsumer);
}
}

View File

@ -0,0 +1,19 @@
package cn.axzo.nanopart.ess.server.utils;
import org.springframework.transaction.annotation.Transactional;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author yanglin
*/
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Transactional(rollbackFor = Exception.class)
public @interface BizTransactional {
}