REQ-3581: 备份
This commit is contained in:
parent
c6521a0cee
commit
7aa7f01817
@ -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);
|
||||
|
||||
}
|
||||
@ -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()) {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
@ -14,9 +14,4 @@ public class CreateContractResponse {
|
||||
*/
|
||||
private String essContractId;
|
||||
|
||||
/**
|
||||
* 预览url, 会过期
|
||||
*/
|
||||
private String previewUrl;
|
||||
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user