REQ-3581: 备份

This commit is contained in:
yanglin 2025-02-17 20:08:57 +08:00
parent 3b06903709
commit a13c06fd12
20 changed files with 219 additions and 129 deletions

View File

@ -3,6 +3,8 @@ package cn.axzo.nanopart.ess.api.domain.contract;
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
import cn.axzo.nanopart.ess.api.enums.EssApproverType;
import cn.axzo.nanopart.ess.api.enums.EssSealType;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
@ -41,12 +43,34 @@ public class Approver implements OrgPerson {
*/
private List<EssSealType> sealTypes;
@JsonIgnore @Override
/**
* 扩展信息, 内部使用
*/
private JSONObject extension;
public void setEssRecipientId(String essRecipientId) {
getOrCreateExtension().put("essRecipientId", essRecipientId);
}
@JsonIgnore @JSONField(serialize = false)
public String getEssRecipientId() {
if (extension == null) return null;
return extension.getString("essRecipientId");
}
@JsonIgnore @JSONField(serialize = false)
public JSONObject getOrCreateExtension() {
if (extension == null)
extension = new JSONObject();
return extension;
}
@JsonIgnore @JSONField(serialize = false)
public Long getOuId() {
return signPerson == null ? 0L : signPerson.getOuId();
}
@JsonIgnore @Override
@JsonIgnore @JSONField(serialize = false)
public Long getPersonId() {
return signPerson == null ? 0L : signPerson.getPersonId();
}

View File

@ -1,14 +0,0 @@
package cn.axzo.nanopart.ess.api.domain.contract;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter @Getter
public class AssignedApprover extends Approver {
private String essRecipientId;
}

View File

@ -62,7 +62,7 @@ public class EssContractInfo {
/**
* 动态签署人信息
*/
private List<AssignedApprover> dynamicApprovers;
private List<Approver> dynamicApprovers;
/**
* 签署方的签署情况

View File

@ -27,10 +27,10 @@ public class CreateContractInfo {
/**
* 是否为动态签署人, 即在创建合同的时候不指定签署人, 而是在获取签署链接时指定签署人
* isDynamicApprover=true时需要指定dynamicApproverSize
* isDynamicApprover=false时, 需要指定approvers
* dynamicApprover=true时不需要指定Approver#signPerson
* dynamicApprover=false时, 需要指定Approver#signPerson
*/
private boolean isDynamicApprover;
private boolean dynamicApprover;
/**
* 合同签署方

View File

@ -36,7 +36,7 @@ public class CreateContractRequest {
* 通过上传PDF发起合同
*/
@Valid
@NotNull
@NotNull(message = "byFile不能为空")
private CreateContractByFile byFile;
@Setter @Getter

View File

@ -1,5 +1,6 @@
package cn.axzo.nanopart.ess.api.request;
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
import lombok.Getter;
import lombok.Setter;
@ -9,7 +10,7 @@ import javax.validation.constraints.NotNull;
* @author yanglin
*/
@Setter @Getter
public class GetPersonAuthStateRequest {
public class GetPersonAuthStateRequest implements OrgPerson {
/**
* 单位id
*/

View File

@ -1,5 +1,6 @@
package cn.axzo.nanopart.ess.server.dao;
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.server.entity.EssContract;
@ -46,12 +47,12 @@ public class EssContractDao extends ServiceImpl<EssContractMapper, EssContract>
public void setEssContractCreated(Long id,
String flowId,
List<String> essFileIds,
List<String> essRecipientIds) {
List<Approver> approvers) {
lambdaUpdate()
.eq(EssContract::getId, id)
.set(EssContract::getEssFieldIds, JSON.toJSONString(essFileIds))
.set(EssContract::getEssContractId, flowId)
.set(EssContract::getEssRecipientIds, JSON.toJSONString(essRecipientIds))
.set(EssContract::getApprovers, JSON.toJSONString(approvers))
.update();
}

View File

@ -1,5 +1,6 @@
package cn.axzo.nanopart.ess.server.dao;
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
import cn.axzo.nanopart.ess.api.enums.EssPersonState;
import cn.axzo.nanopart.ess.server.entity.EssPerson;
import cn.axzo.nanopart.ess.server.mapper.EssPersonMapper;
@ -18,6 +19,14 @@ import java.util.Optional;
@Repository("essPersonDao")
public class EssPersonDao extends ServiceImpl<EssPersonMapper, EssPerson> {
public EssPerson findOrNull(OrgPerson person) {
return find(person.getOuId(), person.getPersonId(), false).orElse(null);
}
public EssPerson findOrNull(Long ouId, Long personId) {
return find(ouId, personId, false).orElse(null);
}
public Optional<EssPerson> find(Long ouId, Long personId) {
return find(ouId, personId, false);
}

View File

@ -1,11 +1,14 @@
package cn.axzo.nanopart.ess.server.dao;
import cn.axzo.nanopart.ess.api.enums.EssSealState;
import cn.axzo.nanopart.ess.api.enums.EssSealType;
import cn.axzo.nanopart.ess.server.entity.EssSeal;
import cn.axzo.nanopart.ess.server.mapper.EssSealMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
@ -27,4 +30,10 @@ public class EssSealDao extends ServiceImpl<EssSealMapper, EssSeal> {
.update();
}
public List<EssSeal> getByOrgAndSealTypes(Long ouId, List<EssSealType> sealTypes) {
return lambdaQuery()
.eq(EssSeal::getOuId, ouId)
.in(CollectionUtils.isNotEmpty(sealTypes), EssSeal::getType, sealTypes)
.list();
}
}

View File

@ -1,9 +1,9 @@
package cn.axzo.nanopart.ess.server.dao;
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
import cn.axzo.nanopart.ess.server.dao.domain.OuAndPersonId;
import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
import cn.axzo.nanopart.ess.server.mapper.EssSealPersonMapper;
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Repository;
@ -37,6 +37,13 @@ public class EssSealPersonDao extends ServiceImpl<EssSealPersonMapper, EssSealPe
.update();
}
public Optional<EssSealPerson> findBySealAndPersonId(String essSealId, Long personId) {
return lambdaQuery()
.eq(EssSealPerson::getEssSealId, essSealId)
.eq(EssSealPerson::getPersonId, personId)
.oneOpt();
}
public List<EssSealPerson> getBySealAndPersonIds(String essSealId, Collection<Long> personIds) {
if (CollectionUtils.isEmpty(personIds))
return Collections.emptyList();

View File

@ -3,7 +3,6 @@ package cn.axzo.nanopart.ess.server.entity;
import cn.axzo.foundation.dao.support.mysql.type.BaseListTypeHandler;
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
import cn.axzo.nanopart.ess.api.domain.contract.AssignedApprover;
import cn.axzo.nanopart.ess.api.domain.contract.EssApproveDetail;
import cn.axzo.nanopart.ess.api.enums.EssContractState;
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
@ -16,6 +15,7 @@ import lombok.Getter;
import lombok.Setter;
import java.util.List;
import java.util.Optional;
/**
* @author yanglin
@ -80,14 +80,8 @@ public class EssContract extends BaseEntity<EssContract> {
/**
* 动态签署人信息
*/
@TableField(typeHandler = AssignedApproverListHandler.class)
private List<AssignedApprover> assignedApprovers;
/**
* 签署方角色编号
*/
@TableField(typeHandler = StringListHandler.class)
private List<String> essRecipientIds;
@TableField(typeHandler = ApproverListHandler.class)
private List<Approver> assignedApprovers;
/**
* 签署方的签署情况
@ -106,10 +100,19 @@ public class EssContract extends BaseEntity<EssContract> {
@TableField(typeHandler = FastjsonTypeHandler.class)
private RecordExt recordExt;
public boolean containsPreciseApprover(OrgPerson person) {
public int preciseApproverSize() {
return approvers.size();
}
public Approver getPreciseApprover(Integer idx) {
return approvers.get(idx);
}
public Optional<Approver> findPreciseApprover(OrgPerson person) {
return approvers.stream()
.anyMatch(approver -> approver.getOuId().equals(person.getOuId())
&& approver.getPersonId().equals(person.getPersonId()));
.filter(approver -> approver.getOuId().equals(person.getOuId())
&& approver.getPersonId().equals(person.getPersonId()))
.findFirst();
}
@Override
@ -127,8 +130,6 @@ public class EssContract extends BaseEntity<EssContract> {
extends BaseListTypeHandler<String> {}
public static class ApproveDetailListHandler
extends BaseListTypeHandler<EssApproveDetail> {}
public static class AssignedApproverListHandler
extends BaseListTypeHandler<AssignedApprover> {}
public static class ApproverListHandler
extends BaseListTypeHandler<Approver> {}
// @formatter:on

View File

@ -6,21 +6,23 @@ import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
import cn.axzo.nanopart.ess.api.domain.OrgPersons;
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
import cn.axzo.nanopart.ess.api.domain.contract.AssignedApprover;
import cn.axzo.nanopart.ess.api.domain.contract.EssApproveDetail;
import cn.axzo.nanopart.ess.api.domain.contract.OrgPersonInfo;
import cn.axzo.nanopart.ess.api.enums.EssContractState;
import cn.axzo.nanopart.ess.api.enums.EssSealType;
import cn.axzo.nanopart.ess.api.request.CreateContractRequest;
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
import cn.axzo.nanopart.ess.api.response.CreateContractResponse;
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
import cn.axzo.nanopart.ess.server.dao.EssOrgDao;
import cn.axzo.nanopart.ess.server.dao.EssPersonDao;
import cn.axzo.nanopart.ess.server.dao.EssSealDao;
import cn.axzo.nanopart.ess.server.dao.EssSealPersonDao;
import cn.axzo.nanopart.ess.server.dao.domain.OuAndPersonId;
import cn.axzo.nanopart.ess.server.entity.EssContract;
import cn.axzo.nanopart.ess.server.entity.EssOrg;
import cn.axzo.nanopart.ess.server.entity.EssPerson;
import cn.axzo.nanopart.ess.server.entity.EssSeal;
import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
import cn.axzo.nanopart.ess.server.ess.domain.JsonObjectAsString;
import cn.axzo.nanopart.ess.server.ess.domain.SealPersons;
@ -31,11 +33,13 @@ import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowByFilesResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.function.Supplier;
@ -58,6 +62,7 @@ public class ContractManager {
private final EssContractDao essContractDao;
private final Broadcaster broadcaster;
private final EssPersonDao essPersonDao;
private final EssSealDao essSealDao;
private final EssSealPersonDao essSealPersonDao;
private final EssSupport essSupport;
@ -71,14 +76,19 @@ public class ContractManager {
ChannelCreateFlowByFilesResponse essResponse = essClient.createContractByFile(
superAdmin, essFileIds, request.getByFile(),
JsonObjectAsString.create().put(CONTRACT_ID, contract.getId()).toString());
List<String> essRecipientIds = EssSupport.collectRecipientIds(essResponse.getApprovers());
for (int i = 0; i < contract.preciseApproverSize(); i++) {
Approver approver = contract.getPreciseApprover(i);
approver.setEssRecipientId(essRecipientIds.get(i));
}
essContractDao.setEssContractCreated(
contract.getId(), essResponse.getFlowId(), essFileIds,
EssSupport.collectRecipientIds(essResponse.getApprovers()));
contract.getId(), essResponse.getFlowId(),
essFileIds, contract.getApprovers());
contract = essContractDao.getOrThrow(essResponse.getFlowId());
broadcaster.fireContractStateChanged(contract);
CreateContractResponse response = new CreateContractResponse();
response.setEssContractId(essResponse.getFlowId());
response.setEssRecipientIds(EssSupport
.collectRecipientIds(essResponse.getApprovers()));
response.setEssRecipientIds(essRecipientIds);
return response;
} catch (TencentCloudSDKException e) {
log.warn("创建合同失败", e);
@ -161,12 +171,12 @@ public class ContractManager {
EssContract contract = essContractDao.find(essContractId, true).orElse(null);
BizAssertions.assertNotNull(contract, "合同不存在: {}", essContractId);
//noinspection DataFlowIssue
OrgPersons<AssignedApprover> approvers = OrgPersons.wrap(contract.getAssignedApprovers());
AssignedApprover approver = approvers.findByPerson(person).orElse(null);
OrgPersons<Approver> approvers = OrgPersons.wrap(contract.getAssignedApprovers());
Approver approver = approvers.findByPerson(person).orElse(null);
// 已经指定过了
if (approver != null)
return;
AssignedApprover otherApprover = approvers.findByOrgId(person.getOuId()).orElse(null);
Approver otherApprover = approvers.findByOrgId(person.getOuId()).orElse(null);
// 该单位下已经指定过签署人了
if (otherApprover != null) {
String message = "该合同已经由其它人签署, 同单位下无法再指定新的签署人";
@ -176,30 +186,49 @@ public class ContractManager {
throw new ServiceException(message);
}
EssPerson contractCreator = getContractCreatorOrThrow(contract);
AssignedApprover assignedApprover = assignApprover(contract, person, essRecipientId);
Approver assignedApprover = assignApprover(contract, person, essRecipientId);
checkApproverSeals(assignedApprover);
essClient.assignApprover(contract.getEssContractId(), contractCreator,
person, assignedApprover.getEssRecipientId());
contract.getAssignedApprovers().add(assignedApprover);
essContractDao.updateAssignedApprovers(contract);
}
private AssignedApprover
assignApprover(EssContract contract, OrgPerson person, String essRecipientId) {
void checkApproverSeals(Approver approver) {
List<EssSealType> sealTypes = approver.getSealTypes();
if (CollectionUtils.isEmpty(sealTypes))
sealTypes = Arrays.stream(EssSealType.values()).collect(toList());
List<EssSeal> seals = essSealDao
.getByOrgAndSealTypes(approver.getOuId(), sealTypes);
BizAssertions.assertNotEmpty(seals, "单位没有指定类型的印章");
boolean found = false;
for (EssSeal seal : seals) {
EssSealPerson sealPerson = essSealPersonDao
.findBySealAndPersonId(seal.getEssSealId(), approver.getPersonId())
.orElse(null);
found = sealPerson != null;
if (found)
break;
}
BizAssertions.assertTrue(found, "签署人员没有指定类型的印章");
}
private Approver assignApprover(EssContract contract, OrgPerson person, String essRecipientId) {
Function<String, Boolean> isRecipientIdUsed = recipientId ->
contract.getAssignedApprovers().stream()
.map(AssignedApprover::getEssRecipientId)
.noneMatch(free -> free.equals(recipientId));
.map(Approver::getEssRecipientId)
.anyMatch(approver -> approver.equals(recipientId));
Supplier<Integer> findFree = () -> {
for (int i = 0; i < contract.getEssRecipientIds().size(); i++) {
String recipientId = contract.getEssRecipientIds().get(i);
for (int i = 0; i < contract.preciseApproverSize(); i++) {
String recipientId = contract.getPreciseApprover(i).getEssRecipientId();
if (!isRecipientIdUsed.apply(recipientId))
return i;
}
return null;
};
Supplier<Integer> findIdx = () -> {
for (int i = 0; i < contract.getEssRecipientIds().size(); i++) {
if (contract.getEssRecipientIds().get(i).equals(essRecipientId))
for (int i = 0; i < contract.preciseApproverSize(); i++) {
if (contract.getPreciseApprover(i).getEssRecipientId().equals(essRecipientId))
return i;
}
return null;
@ -213,10 +242,9 @@ public class ContractManager {
idx = findFree.get();
BizAssertions.assertNotNull(idx, "合同签署人员已满, 无法再指定新的签署人");
}
//noinspection DataFlowIssue
Approver approver = contract.getApprovers().get(idx);
AssignedApprover assignedApprover = BeanMapper.copyBean(approver, AssignedApprover.class);
assignedApprover.setEssRecipientId(contract.getEssRecipientIds().get(idx));
Approver approver = contract.getPreciseApprover(idx);
Approver assignedApprover = BeanMapper.copyBean(approver, Approver.class);
assignedApprover.setEssRecipientId(approver.getEssRecipientId());
OrgPersonInfo signPerson = new OrgPersonInfo();
signPerson.setOuId(person.getOuId());
signPerson.setPersonId(person.getPersonId());
@ -225,9 +253,7 @@ public class ContractManager {
}
public EssPerson getContractCreatorOrThrow(EssContract contract) {
EssPerson creator = essPersonDao
.find(contract.getCreatorOuId(), contract.getCreatorPersonId())
.orElse(null);
EssPerson creator = essPersonDao.findOrNull(contract.getCreatorOuId(), contract.getCreatorPersonId());
BizAssertions.assertNotNull(creator, "找不到合同发起人信息");
return creator;
}

View File

@ -1,9 +1,9 @@
package cn.axzo.nanopart.ess.server.ess;
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
import cn.axzo.nanopart.ess.api.enums.EssEmbedType.EssContext;
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
import cn.axzo.nanopart.ess.api.request.DownloadSingedContractPdfRequest;
import cn.axzo.nanopart.ess.api.request.GetContractSignUrlRequest;
import cn.axzo.nanopart.ess.api.request.GetEmbedWebUrlRequest;
import cn.axzo.nanopart.ess.api.request.RemoveSealAuthorizationRequest;
@ -70,11 +70,8 @@ public class EssService {
EssSealPerson sealPerson = sealAndPerson.getSealPerson();
if (sealPerson.getIsAuthorized().isYes())
return;
EssPerson essPerson = essPersonDao
.find(sealPerson.getOuId(), sealPerson.getPersonId())
.orElse(null);
EssPerson essPerson = essPersonDao.findOrNull(sealPerson);
BizAssertions.assertNotNull(essPerson, "人员不存在: {}", sealPerson.getPersonId());
//noinspection DataFlowIssue
BizAssertions.assertTrue(essPerson.isAuthorized(), "人员未加入单位, 无法授权");
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(sealAndPerson.getSeal().getOuId());
essClient.addSealAuthorization(superAdmin, sealAndPerson.getSeal(), sealPerson);
@ -103,16 +100,16 @@ public class EssService {
public String getContractSignUrl(GetContractSignUrlRequest request) {
EssContract contract = essContractDao.getOrThrow(request.getEssContractId());
EssPerson signPerson = essPersonDao
.find(request.getOuId(), request.getPersonId())
.orElse(null);
EssPerson signPerson = essPersonDao.findOrNull(request);
BizAssertions.assertNotNull(signPerson, "当前签署人员未加入单位, 无法签署");
if (contract.getIsDynamicApprover().isYes()) {
contractManager.tryCreateDynamicApprover(
contract.getEssContractId(), request, request.getEssRecipientId());
} else {
BizAssertions.assertTrue(contract.containsPreciseApprover(request),
"当前签署人员不在合同的签署人员列表中, 无法签署");
Approver approver = contract.findPreciseApprover(request).orElse(null);
BizAssertions.assertNotNull(approver, "当前签署人员不在合同的签署人员列表中, 无法签署");
//noinspection DataFlowIssue
contractManager.checkApproverSeals(approver);
}
String signUrl = "";
if (request.getUrlType() == GetContractSignUrlRequest.URLType.WEIXIN_APP)
@ -122,23 +119,20 @@ public class EssService {
return signUrl;
}
public String getContractPDFUrl(DownloadSingedContractPdfRequest request) {
return getContractPDFUrl(request.getEssContractId());
}
public String getContractPDFUrl(String essContractId) {
EssContract contract = essContractDao.getOrThrow(essContractId);
if (essProps.isContractUrlOss()
if (essProps.isDownloadContractFromOss()
&& contract.getState().isFinalState()
&& StringUtils.isNotBlank(contract.getOssFileKey())) {
return ossService.getOssUrl(contract.getOssFileKey());
}
ossService.maybeDownloadToOss(contract, () -> getContractPDFUrlFromEss(contract));
return getContractPDFUrlFromEss(contract);
}
public String getContractPDFUrlFromEss(EssContract contract) {
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(contract.getCreatorOuId());
return essClient.getContractPDFUrl(superAdmin, contract.getEssContractId());
EssPerson creator = orgManager.getSuperAdminOrThrow(contract.getCreatorOuId());
return essClient.getContractPDFUrl(creator, contract.getEssContractId());
}
}

View File

@ -68,14 +68,6 @@ public class OrgManager {
log.info("add authorized person: {}", person);
}
public void setOrgPersonResigned(Long ouId, Long personId) {
EssPerson person = essPersonDao.find(ouId, personId).orElse(null);
if (person != null) {
essPersonDao.setState(person, EssPersonState.RESIGNED);
log.info("set person resigned: {}", person);
}
}
private EssPerson getOrCreateOrgPerson(Long ouId, Long personId) {
EssPerson person = essPersonDao
.find(ouId, personId, true).orElse(null);
@ -108,10 +100,7 @@ public class OrgManager {
//noinspection DataFlowIssue
if (org.getSuperAdminPersonId() <= 0L)
return Optional.empty();
EssPerson person = essPersonDao
.find(ouId, org.getSuperAdminPersonId())
.orElse(null);
return Optional.ofNullable(person);
return Optional.ofNullable(essPersonDao.findOrNull(ouId, org.getSuperAdminPersonId()));
}
// !! seal
@ -189,4 +178,10 @@ public class OrgManager {
essSealPersonDao.removeById(sealPerson.getId());
}
public void setOrgPersonResign(EssPerson person) {
//EssPerson person = essPersonDao.find(ouId, personId).orElse(null);
essPersonDao.setState(person, EssPersonState.RESIGNED);
log.info("set person resigned: {}", person);
}
}

View File

@ -5,6 +5,8 @@ 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.EssPersonDao;
import cn.axzo.nanopart.ess.server.entity.EssPerson;
import com.alibaba.fastjson.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -23,16 +25,20 @@ import java.util.Collections;
@Slf4j
@Component
@RequiredArgsConstructor
@RocketMQMessageListener(topic = "topic_organizational__${spring.profiles.active}",
consumerGroup = "GID_ess_person_resign_${spring.application.name}_${spring.profiles.active}",
@RocketMQMessageListener(
maxReconsumeTimes = 3,
consumeMode = ConsumeMode.ORDERLY,
nameServer = "${rocketmq.name-server}"
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 {
private final EventConsumer eventConsumer;
private final EssClient essClient;
private final OrgManager orgManager;
private final EssPersonDao essPersonDao;
@Override
public void onMessage(MessageExt message) {
@ -45,11 +51,20 @@ public class PersonResignListener extends BaseListener
OrgUserStatusChangedEvent userEvent = messageEvent.normalizedData(OrgUserStatusChangedEvent.class);
log.info("receive user event: {}", JSON.toJSONString(userEvent));
if (userEvent.getStatusCode() == 6)
orgManager.setOrgPersonResigned(userEvent.getOuId(), userEvent.getPersonId());
else
trySetPersonResigned(userEvent);
else
log.info("ignore user event: {}", JSON.toJSONString(userEvent));
}
private void trySetPersonResigned(OrgUserStatusChangedEvent userEvent) {
EssPerson person = essPersonDao.findOrNull(userEvent.getOuId(), userEvent.getPersonId());
if (person == null) return;
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(userEvent.getOuId());
essClient.setEmployeeResigned(superAdmin, Collections.singletonList(person));
orgManager.setOrgPersonResign(person);
log.info("set person resigned: {}", JSON.toJSONString(person));
}
@Override
public void afterPropertiesSet() {
eventConsumer.registerHandlers(Collections.singletonList(

View File

@ -77,9 +77,7 @@ public class QueryService {
public GetPersonAuthStateResponse
getPersonAuthState(GetPersonAuthStateRequest request) {
EssPerson person = essPersonDao
.find(request.getOuId(), request.getPersonId())
.orElse(null);
EssPerson person = essPersonDao.findOrNull(request);
GetPersonAuthStateResponse response = new GetPersonAuthStateResponse();
response.setAuthorized(person != null && person.isAuthorized());
return response;

View File

@ -154,10 +154,8 @@ class CallbackController implements EssCallbackApi, InitializingBean {
}
if (contract != null) {
contractManager.updateContractState(contract, state, approveDetails);
if (state.isFinalState() && contract.getOssFileKey() == null) {
String pdfUrlFromEss = essService.getContractPDFUrlFromEss(contract);
ossService.downloadAndUploadToOss(contract, pdfUrlFromEss);
}
EssContract finalContract = contract;
ossService.maybeDownloadToOss(contract, () -> essService.getContractPDFUrlFromEss(finalContract));
}
return changes.getFlowId();
});

View File

@ -28,7 +28,7 @@ public class EssProps {
private boolean testEnv;
private boolean contractUrlOss;
private boolean downloadContractFromOss = true;
private String ossAppCode = "elec-signature-contract";

View File

@ -108,7 +108,6 @@ public class EssSupport {
request.getByFile().isDynamicApprover()));
contract.setApprovers(request.getByFile().getApprovers());
contract.setAssignedApprovers(Collections.emptyList());
contract.setEssRecipientIds(Collections.emptyList());
contract.setApproveDetails(Collections.emptyList());
return contract;
}

View File

@ -1,5 +1,6 @@
package cn.axzo.nanopart.ess.server.ess.support;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
import cn.axzo.nanopart.ess.server.entity.EssContract;
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
@ -11,8 +12,8 @@ import cn.axzo.oss.http.model.ApiSignUrlUploadResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@ -21,8 +22,12 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Supplier;
/**
* @author yanglin
@ -32,10 +37,21 @@ import java.util.List;
@RequiredArgsConstructor
public class OssService {
private final TransactionTemplate transactionTemplate;
private final ServerFileServiceApi serverFileServiceApi;
private final EssContractDao essContractDao;
private final ServerFileServiceApi serverFileServiceApi;
private final EssProps essProps;
private final ExecutorService executor = Executors.newSingleThreadExecutor();
public void maybeDownloadToOss(EssContract contract, Supplier<String> essPdfUrl) {
executor.execute(() -> {
if (!contract.getState().isFinalState()
|| StringUtils.isNotBlank(contract.getOssFileKey()))
return;
String fileName = String.format("%s.pdf", contract.getContractName());
String fileKey = saveToOss(essPdfUrl.get(), fileName);
essContractDao.setOssInfo(contract, fileKey);
});
}
public String getOssUrl(String fileKey) {
ApiSignUrlDownloadRequest request = new ApiSignUrlDownloadRequest();
@ -47,21 +63,22 @@ public class OssService {
return CollectionUtils.isEmpty(responses) ? null : responses.get(0).getSignUrl();
}
public void downloadAndUploadToOss(EssContract contract, String pdfUrlFromEss) {
public String saveToOss(String contentUrl, String fileName) {
try {
ApiSignUrlUploadResponse ossResponse = prepareOss(contract);
streamUpload(ossResponse.getSignUrl(), urlDownload(pdfUrlFromEss));
essContractDao.setOssInfo(contract, ossResponse.getFileKey());
ApiSignUrlUploadResponse ossResponse = prepareOss(fileName);
streamUpload(ossResponse, urlDownload(contentUrl), fileName);
return ossResponse.getFileKey();
} catch (Exception e) {
log.warn("下载合同并上传到OSS失败", e);
throw new ServiceException("下载合同并上传到OSS失败", e);
}
}
private ApiSignUrlUploadResponse prepareOss(EssContract contract) {
private ApiSignUrlUploadResponse prepareOss(String fileName) {
ApiSignUrlUploadRequest ossRequest = new ApiSignUrlUploadRequest();
ossRequest.setAppCode(essProps.getOssAppCode());
ossRequest.setBizScene(essProps.getOssBizScene());
ossRequest.setFileName(String.format("%s.pdf", contract.getContractName()));
ossRequest.setFileName(fileName);
return BizAssertions
.assertResponse(serverFileServiceApi.signUrlFetchUpload(ossRequest));
}
@ -70,7 +87,7 @@ public class OssService {
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("GET");
con.setConnectTimeout(4 * 1000);
InputStream inStream = con.getInputStream(); //通过输入流获取图片数据
InputStream inStream = con.getInputStream();
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[2048];
int len;
@ -80,22 +97,32 @@ public class OssService {
return outStream.toByteArray();
}
private void streamUpload(String uploadUrl, byte[] content) throws IOException {
HttpURLConnection connection = (HttpURLConnection) new URL(uploadUrl).openConnection();
connection.setRequestMethod("POST");
private void streamUpload(ApiSignUrlUploadResponse ossResponse,
byte[] content,
String fileName) throws IOException {
HttpURLConnection connection = (HttpURLConnection)
new URL(ossResponse.getSignUrl()).openConnection();
connection.setRequestMethod("PUT");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/octet-stream");
try (OutputStream os = connection.getOutputStream()) {
ByteArrayInputStream is = new ByteArrayInputStream(content);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1)
os.write(buffer, 0, bytesRead);
os.flush();
connection.setRequestProperty("Host", ossResponse.getHost());
connection.setRequestProperty("Content-Type", ossResponse.getContentType());
connection.setRequestProperty("Content-Disposition", String.format(
"attachment;filename=\"%s\"", URLEncoder.encode(fileName, "utf-8")));
try {
try (OutputStream os = connection.getOutputStream()) {
ByteArrayInputStream is = new ByteArrayInputStream(content);
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = is.read(buffer)) != -1)
os.write(buffer, 0, bytesRead);
os.flush();
}
int responseCode = connection.getResponseCode();
log.info("上传到OSS返回码: {}", responseCode);
} finally {
connection.disconnect();
}
int responseCode = connection.getResponseCode();
log.info("上传到OSS返回码: {}", responseCode);
connection.disconnect();
}
}