REQ-3581: 备份

This commit is contained in:
yanglin 2025-02-13 11:39:00 +08:00
parent c6521a0cee
commit 7aa7f01817
13 changed files with 314 additions and 128 deletions

View File

@ -14,6 +14,7 @@ import cn.axzo.nanopart.ess.api.request.GetSealsRequest;
import cn.axzo.nanopart.ess.api.request.GetUnitAuthStatesRequest;
import cn.axzo.nanopart.ess.api.request.RemoveSealAuthorizationRequest;
import cn.axzo.nanopart.ess.api.request.RemoveSealPersonRequest;
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
import cn.axzo.nanopart.ess.api.response.CreateConsoleLoginUrlResponse;
import cn.axzo.nanopart.ess.api.response.CreateContractResponse;
import cn.axzo.nanopart.ess.api.response.DownloadSingedContractPdfResponse;
@ -118,4 +119,11 @@ public interface EssApi {
ApiResult<DownloadSingedContractPdfResponse> getContractPDFUrl(
@RequestBody @Valid DownloadSingedContractPdfRequest request);
/**
* 撤销合同
*/
@PostMapping("api/ess/revokeContract")
ApiResult<Void> revokeContract(
@RequestBody @Valid RevokeContractRequest request);
}

View File

@ -11,20 +11,21 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public enum EssContractState {
INIT("合同创建"),
PART("合同签署中"),
ALL("合同签署完成"),
REJECT("合同拒签"),
CANCEL("合同撤回"),
WILLEXPIRE("合同即将过期"),
DEADLINE("合同流签(合同过期)"),
RELIEVED("解除协议(已解除)"),
INVALID("合同失效"),
EXCEPTION("合同异常"),
INIT("合同创建", false),
PART("合同签署中", false),
ALL("合同签署完成", true),
REJECT("合同拒签", true),
CANCEL("合同撤回", true),
WILLEXPIRE("合同即将过期", false),
DEADLINE("合同流签(合同过期)", true),
RELIEVED("解除协议(已解除)", true),
INVALID("合同失效", true),
EXCEPTION("合同异常", true),
;
private final String description;
private final boolean finalState;
public static EssContractState fromEssCode(String code) {
for (EssContractState value : values()) {

View File

@ -3,7 +3,7 @@ package cn.axzo.nanopart.ess.api.enums;
import lombok.Getter;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* @author yanglin
@ -27,8 +27,8 @@ public enum EssSealType {
this.essCodes = essCodes;
}
public void collectEssCodes(Collection<String> essCodes) {
essCodes.addAll(Arrays.asList(this.essCodes));
public List<String> getEssCodes() {
return Arrays.asList(essCodes);
}
public static EssSealType fromEssCode(String essCode) {

View File

@ -0,0 +1,21 @@
package cn.axzo.nanopart.ess.api.request;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotEmpty;
import java.util.List;
/**
* @author yanglin
*/
@Setter @Getter
public class CreateContractByFile extends CreateContractInfo {
/**
* 合同文件base64: Base64.getEncoder().encodeToString(file.getBytes())
*/
@NotEmpty(message = "base64Files不能为空")
private List<String> base64Files;
}

View File

@ -0,0 +1,96 @@
package cn.axzo.nanopart.ess.api.request;
import cn.axzo.nanopart.ess.api.enums.EssSealType;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Set;
import static java.util.stream.Collectors.toSet;
/**
* @author yanglin
*/
@Setter @Getter
public class CreateContractInfo {
/**
* 合同名称
*/
@NotBlank(message = "contractName不能为空")
private String contractName;
/**
* 合同签署方
*/
@Valid
@NotEmpty(message = "approvers不能为空")
private List<ApproverInfo> approvers;
/**
* 签署方签署控件印章/签名等的生成方式.
* 0: 在合同流程发起时由发起人指定签署方的签署控件的位置和数量
* 1: 签署方在签署时自行添加签署控件可以拖动位置和控制数量
*/
private Long signBeanTag = 1L;
/**
* 是否按 approvers 中指定的顺序进行签署
*/
private boolean signOrdered = false;
@JsonIgnore
public Set<Long> getApproverOuIds() {
return approvers.stream()
.map(ApproverInfo::getOuId)
.collect(toSet());
}
@Setter @Getter
public static class ApproverInfo {
/**
* 签署方单位id
*/
@NotNull(message = "ouId不能为空")
private Long ouId;
/**
* 签署人员id
*/
@NotNull(message = "personId不能为空")
private Long personId;
/**
* 在指定签署方时可选择企业B端或个人C端等不同的参与者类型
*/
@NotNull(message = "approverType不能为空")
private ApproverType approverType = ApproverType.ORGANIZATION;
/**
* 签署方在签署合同之前需要强制阅读合同的时长可指定为3秒至300秒之间的任意值
*/
@NotNull(message = "preReadTime不能为空")
private Long preReadTime = 10L;
/**
* 指定盖的章的类型
*/
private List<EssSealType> sealTypes;
}
public enum ApproverType {
// 企业/ 企业员工
ORGANIZATION,
// 企业/ 企业员工自动签
ENTERPRISESERVER
}
}

View File

@ -1,17 +1,11 @@
package cn.axzo.nanopart.ess.api.request;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.List;
import java.util.Set;
import static java.util.stream.Collectors.toSet;
/**
* @author yanglin
@ -39,30 +33,10 @@ public class CreateContractRequest {
private OperatorInfo operator;
/**
* 合同名称
*/
@NotBlank(message = "contractName不能为空")
private String contractName;
/**
* 合同签署方
* 通过上传PDF发起合同
*/
@Valid
@NotEmpty(message = "approvers不能为空")
private List<ApproverInfo> approvers;
/**
* 合同文件base64. Base64.getEncoder().encodeToString(file.getBytes())
*/
@NotBlank(message = "fileBase64不能为空")
private String fileBase64;
@JsonIgnore
public Set<Long> getApproverOuIds() {
return approvers.stream()
.map(ApproverInfo::getOuId)
.collect(toSet());
}
private CreateContractByFile byFile;
@Setter @Getter
public static class OperatorInfo {
@ -81,21 +55,4 @@ public class CreateContractRequest {
}
@Setter @Getter
public static class ApproverInfo {
/**
* 签署方单位id
*/
@NotNull(message = "ouId不能为空")
private Long ouId;
/**
* 签署人员id
*/
@NotNull(message = "personId不能为空")
private Long personId;
}
}

View File

@ -0,0 +1,24 @@
package cn.axzo.nanopart.ess.api.request;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
/**
* @author yanglin
*/
@Setter @Getter
public class RevokeContractRequest {
/**
* 合同id
*/
@NotBlank(message = "essContractId不能为空")
private String essContractId;
/**
* 撤销原因
*/
private String reason;
}

View File

@ -14,9 +14,4 @@ public class CreateContractResponse {
*/
private String essContractId;
/**
* 预览url, 会过期
*/
private String previewUrl;
}

View File

@ -3,9 +3,11 @@ package cn.axzo.nanopart.ess.server.dao;
import cn.axzo.nanopart.ess.api.enums.EssContractState;
import cn.axzo.nanopart.ess.server.entity.EssContract;
import cn.axzo.nanopart.ess.server.mapper.EssContractMapper;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/**
@ -20,10 +22,10 @@ public class EssContractDao extends ServiceImpl<EssContractMapper, EssContract>
.oneOpt();
}
public void setEssContractCreated(Long id, String essFileId, String essContractId) {
public void setEssContractCreated(Long id, List<String> essFileIds, String essContractId) {
lambdaUpdate()
.eq(EssContract::getId, id)
.set(EssContract::getEssFieldId, essFileId)
.set(EssContract::getEssFieldIds, JSON.toJSONString(essFileIds))
.set(EssContract::getEssContractId, essContractId)
.update();
}

View File

@ -11,6 +11,8 @@ import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
/**
* @author yanglin
*/
@ -52,7 +54,8 @@ public class EssContract extends BaseEntity<EssContract> {
/**
* 腾讯电子签的资源id
*/
private String essFieldId;
@TableField(typeHandler = StringListHandler.class)
private List<String> essFieldIds;
/**
* 合同状态. INIT: 合同创建, PART: 合同签署中, ALL: 合同签署完成, REJECT: 合同拒签, CANCEL: 合同撤回, WILLEXPIRE: 合同即将过期, DEADLINE: 合同流签(合同过期), RELIEVED: 解除协议已解除), INVALID: 合同已失效, EXCEPTION: 合同异常
@ -82,16 +85,12 @@ public class EssContract extends BaseEntity<EssContract> {
return JSON.toJSONString(this);
}
@Setter @Getter
public static class Approver {
}
@Setter @Getter
public static class RecordExt {
}
// @formatter:off
public static class ApproversHandler
extends BaseListTypeHandler<Approver> {}
public static class StringListHandler
extends BaseListTypeHandler<String> {}
// @formatter:on
}

View File

@ -2,15 +2,19 @@ package cn.axzo.nanopart.ess.server.ess;
import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.nanopart.ess.api.enums.EssContractState;
import cn.axzo.nanopart.ess.api.request.CreateContractInfo;
import cn.axzo.nanopart.ess.api.request.CreateContractRequest;
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
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.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.EssSealPerson;
import cn.axzo.nanopart.ess.server.ess.EssClient.UploadFileBusinessType;
import cn.axzo.nanopart.ess.server.ess.domain.SealPersons;
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
import com.alibaba.fastjson.JSON;
@ -20,6 +24,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.List;
import static java.util.stream.Collectors.toList;
@ -37,17 +42,18 @@ public class ContractManager {
private final EssOrgDao essOrgDao;
private final EssContractDao essContractDao;
private final Broadcaster broadcaster;
private final EssPersonDao essPersonDao;
private final EssSealPersonDao essSealPersonDao;
public String createContract(CreateContractRequest request) {
check(request);
checkPermission(request);
EssContract contract = saveContract(request);
try {
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(request.getOperator().getOuId());
String essFileId = essClient.uploadFile(superAdmin, request.getFileBase64());
String essContractId = essClient.createContract(superAdmin,
request.getContractName(), essFileId, getApproverAsSealPersons(request));
essContractDao.setEssContractCreated(contract.getId(), essFileId, essContractId);
List<String> essFileIds = essClient.uploadFile(
superAdmin, UploadFileBusinessType.DOCUMENT, request.getByFile().getBase64Files());
String essContractId = essClient.createContractByFile(superAdmin, essFileIds, request.getByFile());
essContractDao.setEssContractCreated(contract.getId(), essFileIds, essContractId);
broadcaster.fireContractStateChanged(contract.getEssContractId());
return essContractId;
} catch (TencentCloudSDKException e) {
@ -58,8 +64,9 @@ public class ContractManager {
}
}
private void check(CreateContractRequest request) {
List<EssOrg> orgs = essOrgDao.getByOuIds(request.getApproverOuIds());
private void checkPermission(CreateContractRequest request) {
BizAssertions.assertNotNull(request.getByFile(), "合同PDF文件不能为空");
List<EssOrg> orgs = essOrgDao.getByOuIds(request.getByFile().getApproverOuIds());
List<String> notAuthorizedOrgs = orgs.stream()
.filter(i -> i.getIsAuthorized().isNo())
.map(EssOrg::getOuName)
@ -67,16 +74,16 @@ public class ContractManager {
BizAssertions.assertEmpty(notAuthorizedOrgs,
"创建合同失败. 以下单位还未认证: {}", JSON.toJSONString(notAuthorizedOrgs));
SealPersons sealPersons = SealPersons.wrap(getApproverAsSealPersons(request));
for (CreateContractRequest.ApproverInfo approver : request.getApprovers()) {
for (CreateContractInfo.ApproverInfo approver : request.getByFile().getApprovers()) {
EssSealPerson sealPerson = sealPersons.find(
approver.getOuId(), approver.getPersonId()).orElse(null);
BizAssertions.assertFalse(sealPerson == null || sealPerson.getIsAuthorized().isNo(),
"创建合同失败. 部分签署人员没有印章授权");
"创建合同失败. 部分签署人员没有印章授权, ouId={}, personId={}", approver.getOuId(), approver.getPersonId());
}
}
private List<EssSealPerson> getApproverAsSealPersons(CreateContractRequest request) {
List<OuAndPersonId> ouAndPersonIds = request.getApprovers().stream()
List<OuAndPersonId> ouAndPersonIds = request.getByFile().getApprovers().stream()
.map(approver -> OuAndPersonId.create(approver.getOuId(), approver.getPersonId()))
.distinct()
.collect(toList());
@ -89,11 +96,11 @@ public class ContractManager {
contract.setBizCode(request.getBizCode());
contract.setCreatorOuId(request.getOperator().getOuId());
contract.setCreatorPersonId(request.getOperator().getPersonId());
contract.setContractName(request.getContractName());
contract.setContractName(request.getByFile().getContractName());
contract.setEssContractId("");
contract.setEssFieldId("");
contract.setEssFieldIds(Collections.emptyList());
contract.setState(EssContractState.INIT);
contract.setApprovers(request.getApprovers());
contract.setApprovers(request.getByFile().getApprovers());
try {
essContractDao.save(contract);
return contract;
@ -106,4 +113,18 @@ public class ContractManager {
essContractDao.updateState(essContractId, state);
broadcaster.fireContractStateChanged(essContractId);
}
}
public void revokeContract(RevokeContractRequest request) {
EssContract contract = essContractDao.find(request.getEssContractId()).orElse(null);
BizAssertions.assertNotNull(contract, "合同不存在: {}", request.getEssContractId());
//noinspection DataFlowIssue
BizAssertions.assertFalse(contract.getState().isFinalState(),
"合同已是最终状态[{}], 无法撤销", contract.getState().getDescription());
EssPerson creator = essPersonDao
.find(contract.getCreatorOuId(), contract.getCreatorPersonId(), false)
.orElse(null);
essClient.revokeContract(creator, contract.getEssContractId(), request.getReason());
essContractDao.updateState(request.getEssContractId(), EssContractState.CANCEL);
}
}

View File

@ -5,6 +5,8 @@ import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
import cn.axzo.nanopart.ess.api.enums.EssConsoleUrlEndpoint;
import cn.axzo.nanopart.ess.api.enums.EssEmbedType;
import cn.axzo.nanopart.ess.api.request.CreateContractInfo;
import cn.axzo.nanopart.ess.api.request.CreateContractInfo.ApproverInfo;
import cn.axzo.nanopart.ess.server.dao.EssLogDao;
import cn.axzo.nanopart.ess.server.entity.EssLog;
import cn.axzo.nanopart.ess.server.entity.EssOrg;
@ -24,6 +26,7 @@ import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.essbasic.v20210526.EssbasicClient;
import com.tencentcloudapi.essbasic.v20210526.models.Agent;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCancelFlowRequest;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateEmbedWebUrlRequest;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateEmbedWebUrlResponse;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowByFilesRequest;
@ -34,6 +37,7 @@ import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateSealPolicyRequ
import com.tencentcloudapi.essbasic.v20210526.models.ChannelDeleteSealPoliciesRequest;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelDescribeEmployeesRequest;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelDescribeEmployeesResponse;
import com.tencentcloudapi.essbasic.v20210526.models.ComponentLimit;
import com.tencentcloudapi.essbasic.v20210526.models.CreateConsoleLoginUrlRequest;
import com.tencentcloudapi.essbasic.v20210526.models.CreateConsoleLoginUrlResponse;
import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsRequest;
@ -48,6 +52,7 @@ import com.tencentcloudapi.essbasic.v20210526.models.UserInfo;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@ -59,9 +64,13 @@ import org.springframework.util.ReflectionUtils;
import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static cn.axzo.nanopart.ess.server.ess.EssClient.Invocation.invocation;
import static java.util.function.Function.identity;
@ -77,12 +86,13 @@ import static java.util.stream.Collectors.toMap;
public class EssClient implements InitializingBean {
private static final String NEW_TRANSACTION = "essLogTransactionTemplate";
private static final Pattern ESS_ERROR_REQUEST_ID_PATTERN = Pattern.compile("RequestId:([a-f0-9\\-]+)");
private final EssProps props;
private final EssLogDao essLogDao;
private final EssSupport essSupport;
@Resource(name = NEW_TRANSACTION)
private TransactionTemplate transactionTemplate;
private TransactionTemplate newTransaction;
private EssbasicClient manage;
private EssbasicClient file;
@ -119,7 +129,7 @@ public class EssClient implements InitializingBean {
request.setHiddenComponents(true);
ChannelCreateEmbedWebUrlResponse response = exec(invocation()
.context("ChannelCreateEmbedWebUrl")
.subject(businessId == null ? "" : businessId)
.subject(businessId == null ? embedType.name() : businessId)
.request(request)
.func(() -> manage.ChannelCreateEmbedWebUrl(request)));
return response.getWebUrl();
@ -153,62 +163,77 @@ public class EssClient implements InitializingBean {
.func(() -> manage.ChannelDeleteSealPolicies(request)));
}
String uploadFile(EssPerson superAdmin, String fileBase64) throws TencentCloudSDKException {
List<String> uploadFile(EssPerson superAdmin,
UploadFileBusinessType businessType,
List<String> base64Files) throws TencentCloudSDKException {
ArrayList<UploadFile> files = new ArrayList<>();
for (String base64File : base64Files) {
UploadFile file = new UploadFile();
file.setFileBody(base64File);
files.add(file);
}
UploadFilesRequest request = new UploadFilesRequest();
request.setAgent(agent(superAdmin));
request.setFileInfos(new UploadFile[]{new UploadFile()});
request.getFileInfos()[0].setFileBody(fileBase64);
request.setBusinessType("DOCUMENT");
UploadFilesResponse response = call(invocation()
request.setFileInfos(files.toArray(new UploadFile[0]));
request.setBusinessType(businessType.name());
UploadFilesResponse response = call(Invocation.<UploadFilesResponse>invocation()
.context("UploadFiles")
.subject("")
.subject2(r -> r.getFileIds()[0])
.request(request)
.func(() -> file.UploadFiles(request)));
return response.getFileIds()[0];
return Arrays.asList(response.getFileIds());
}
String createContract(
EssPerson superAdmin,
String contractName,
String contractFileId,
List<EssSealPerson> approvePersons
) throws TencentCloudSDKException {
String createContractByFile(EssPerson superAdmin,
List<String> contractFileIds,
CreateContractInfo contractInfo) throws TencentCloudSDKException {
Map<Long, OrganizationalUnitVO> orgProfiles = essSupport
.getOrgProfiles(approvePersons.stream()
.map(EssSealPerson::getOuId)
.getOrgProfiles(contractInfo.getApprovers().stream()
.map(ApproverInfo::getOuId)
.collect(toList())).stream()
.collect(toMap(OrganizationalUnitVO::getId, identity()));
Map<Long, PersonProfileDto> personProfiles = essSupport
.getPersonProfiles(approvePersons.stream()
.map(EssSealPerson::getPersonId)
.getPersonProfiles(contractInfo.getApprovers().stream()
.map(ApproverInfo::getPersonId)
.collect(toList())).stream()
.collect(toMap(PersonProfileDto::getId, identity()));
ArrayList<FlowApproverInfo> approvers = new ArrayList<>();
for (EssSealPerson approvePerson : approvePersons) {
OrganizationalUnitVO orgProfile = orgProfiles.get(approvePerson.getOuId());
BizAssertions.assertNotNull(orgProfile, "找不到单位信息: ", approvePerson.getOuId());
PersonProfileDto personProfile = personProfiles.get(approvePerson.getPersonId());
BizAssertions.assertNotNull(personProfile, "找不到人员信息: ", approvePerson.getPersonId());
for (ApproverInfo approverInfo : contractInfo.getApprovers()) {
OrganizationalUnitVO orgProfile = orgProfiles.get(approverInfo.getOuId());
BizAssertions.assertNotNull(orgProfile, "找不到单位信息: ", approverInfo.getOuId());
PersonProfileDto personProfile = personProfiles.get(approverInfo.getPersonId());
BizAssertions.assertNotNull(personProfile, "找不到人员信息: ", approverInfo.getPersonId());
FlowApproverInfo approver = new FlowApproverInfo();
approvers.add(approver);
approver.setName(personProfile.getRealName());
approver.setMobile(personProfile.getPhone());
approver.setOpenId(PersonOpenId.create(approvePerson.getOuId(), approvePerson.getPersonId()).toOpenId());
approver.setOpenId(PersonOpenId.create(approverInfo.getOuId(), approverInfo.getPersonId()).toOpenId());
approver.setOrganizationName(orgProfile.getName());
approver.setOrganizationOpenId(OuOpenId.create(approvePerson.getOuId()).toOpenId());
approver.setApproverType("ORGANIZATION");
approver.setOrganizationOpenId(OuOpenId.create(approverInfo.getOuId()).toOpenId());
approver.setApproverType(approverInfo.getApproverType().name());
approver.setNotifyType("NONE");
approver.setPreReadTime(10L);
approver.setPreReadTime(approverInfo.getPreReadTime());
if (CollectionUtils.isNotEmpty(approverInfo.getSealTypes())) {
ComponentLimit componentLimit = new ComponentLimit();
componentLimit.setComponentType("SIGN_SEAL");
componentLimit.setComponentValue(approverInfo.getSealTypes()
.stream().flatMap(type -> type.getEssCodes().stream())
.distinct().toArray(String[]::new));
approver.setAddSignComponentsLimits(new ComponentLimit[]{componentLimit});
}
}
ChannelCreateFlowByFilesRequest request = new ChannelCreateFlowByFilesRequest();
request.setAgent(agent(superAdmin));
request.setSignBeanTag(1L);
request.setFlowName(contractName);
request.setFileIds(new String[]{contractFileId});
request.setSignBeanTag(contractInfo.getSignBeanTag());
request.setFlowName(contractInfo.getContractName());
request.setFileIds(contractFileIds.toArray(new String[0]));
request.setFlowApprovers(approvers.toArray(new FlowApproverInfo[0]));
ChannelCreateFlowByFilesResponse response = call(invocation()
request.setUnordered(!contractInfo.isSignOrdered());
ChannelCreateFlowByFilesResponse response = call(Invocation.<ChannelCreateFlowByFilesResponse>invocation()
.context("ChannelCreateFlowByFiles")
.subject(contractName)
.subject(contractInfo.getContractName())
.subject2(ChannelCreateFlowByFilesResponse::getFlowId)
.request(request)
.func(() -> manage.ChannelCreateFlowByFiles(request)));
return response.getFlowId();
@ -290,28 +315,34 @@ public class EssClient implements InitializingBean {
return new EssbasicClient(cred, "", clientProfile);
}
private <T> T exec(Invocation.InvocationBuilder builder) {
private <T> T exec(Invocation.InvocationBuilder<?> builder) {
try {
return call(builder);
} catch (TencentCloudSDKException e) {
throw new ServiceException(String.format("腾讯云接口调用失败: %s", e.getMessage()), e);
throw new ServiceException(String.format("腾讯返回: %s", e.getMessage()), e);
}
}
private <T> T call(Invocation.InvocationBuilder builder) throws TencentCloudSDKException {
Invocation invocation = builder.build();
private <T> T call(Invocation.InvocationBuilder<?> builder) throws TencentCloudSDKException {
//noinspection unchecked
Invocation<Object> invocation = (Invocation<Object>) builder.build();
EssLog essLog = new EssLog();
essLog.setCreateAt(new Date());
essLog.setUpdateAt(new Date());
essLog.setContext(String.format("ess:%s", invocation.context));
essLog.setSubject(invocation.subject == null ? "" : invocation.subject);
essLog.addLogContent("essRequest", invocation.request);
essLog.setSubject(invocation.subject == null ? "" : invocation.subject);
T response = null;
TencentCloudSDKException exception = null;
try {
//noinspection unchecked
response = (T) invocation.func.exec();
essLog.addLogContent("essResponse", response);
if (invocation.subject2 != null) {
String newSubject = invocation.subject2.apply(response);
if (newSubject != null) essLog.setSubject(newSubject);
}
if (response != null) {
Method method = ReflectionUtils.findMethod(response.getClass(), "getRequestId");
if (method != null) {
@ -324,22 +355,46 @@ public class EssClient implements InitializingBean {
log.warn("腾讯云接口调用失败", e);
exception = e;
essLog.setIsError(YesOrNo.YES);
essLog.addLogContent("exception", Throwables.getStackTraceAsString(e));
String stackTraceAsString = Throwables.getStackTraceAsString(e);
essLog.addLogContent("exception", stackTraceAsString);
Matcher matcher = ESS_ERROR_REQUEST_ID_PATTERN.matcher(stackTraceAsString);
if (matcher.find()) {
String requestId = matcher.group(1);
essLog.setRequestId(requestId);
}
} finally {
newTransaction.executeWithoutResult(unused -> essLogDao.save(essLog));
}
transactionTemplate.executeWithoutResult(unused -> essLogDao.save(essLog));
if (exception != null)
throw exception;
return response;
}
void revokeContract(EssPerson creator, String essContractId, String reason) {
ChannelCancelFlowRequest request = new ChannelCancelFlowRequest();
request.setAgent(agent(creator));
request.setFlowId(essContractId);
request.setCancelMessage(reason);
exec(invocation()
.context("ChannelCancelFlow")
.subject(essContractId)
.request(request)
.func(() -> manage.ChannelCancelFlow(request)));
}
public enum UploadFileBusinessType {
DOCUMENT, TEMPLATE
}
@Builder
public static class Invocation {
public static class Invocation<T> {
final String context;
final String subject;
final Function<T, String> subject2;
final Object request;
final TencentCloudFunc<?> func;
final TencentCloudFunc<T> func;
public static InvocationBuilder invocation() {
public static <T> InvocationBuilder<T> invocation() {
return Invocation.builder();
}

View File

@ -16,6 +16,7 @@ import cn.axzo.nanopart.ess.api.request.GetSealsRequest;
import cn.axzo.nanopart.ess.api.request.GetUnitAuthStatesRequest;
import cn.axzo.nanopart.ess.api.request.RemoveSealAuthorizationRequest;
import cn.axzo.nanopart.ess.api.request.RemoveSealPersonRequest;
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
import cn.axzo.nanopart.ess.api.request.SealAndPersonRequest;
import cn.axzo.nanopart.ess.api.response.CreateConsoleLoginUrlResponse;
import cn.axzo.nanopart.ess.api.response.CreateContractResponse;
@ -185,4 +186,10 @@ class ApiController implements EssApi {
return ApiResult.ok(response);
}
@Override
public ApiResult<Void> revokeContract(RevokeContractRequest request) {
contractManager.revokeContract(request);
return ApiResult.ok();
}
}