Merge branch 'master' into feature/REQ-3540
# Conflicts: # nanopart-server/pom.xml # pom.xml
This commit is contained in:
commit
59ff764e29
44
ess/ess-api/pom.xml
Normal file
44
ess/ess-api/pom.xml
Normal file
@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<artifactId>ess</artifactId>
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>ess-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<name>ess-api</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-common-domain</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework.rocketmq</groupId>
|
||||
<artifactId>axzo-common-rocketmq</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-httpclient</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
146
ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/EssApi.java
Normal file
146
ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/EssApi.java
Normal file
@ -0,0 +1,146 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.nanopart.ess.api.domain.EssOrgAndSealInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.EssSealPersonInfo;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealPersonRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AssignSignUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.DownloadSingedContractPdfRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetContractDetailByContractIdRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetEmbedWebUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetOrgAuthStatesRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetPersonAuthStateRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetSealPersonRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetSealsRequest;
|
||||
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.SaveContractSnapshotRequest;
|
||||
import cn.axzo.nanopart.ess.api.response.AssignSignUrlResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateConsoleLoginUrlResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateContractByFileResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.DownloadSingedContractPdfResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetContractDetailByContractIdResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetEmbedWebUrlResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetOrgAuthStatesResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetPersonAuthStateResponse;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
|
||||
public interface EssApi {
|
||||
|
||||
/**
|
||||
* 查询单位电子签开通情况
|
||||
*/
|
||||
@PostMapping("api/ess/getOrgAuthStates")
|
||||
ApiResult<List<GetOrgAuthStatesResponse>> getOrgAuthStates(@RequestBody @Valid GetOrgAuthStatesRequest request);
|
||||
|
||||
/**
|
||||
* 查询用户电子签开通情况(认证)
|
||||
*/
|
||||
@PostMapping("api/ess/getPersonAuthState")
|
||||
ApiResult<GetPersonAuthStateResponse> getPersonAuthState(@RequestBody @Valid GetPersonAuthStateRequest request);
|
||||
|
||||
/**
|
||||
* 获取电子签登录链接
|
||||
*/
|
||||
@PostMapping("api/ess/createConsoleLoginUrl")
|
||||
ApiResult<CreateConsoleLoginUrlResponse> createConsoleLoginUrl(
|
||||
@RequestBody @Valid CreateConsoleLoginUrlRequest request);
|
||||
|
||||
/**
|
||||
* 获取内嵌页面链接, 有效期为5分钟
|
||||
*/
|
||||
@PostMapping("api/ess/getEmbedWebUrl")
|
||||
ApiResult<GetEmbedWebUrlResponse> getEmbedWebUrl(@RequestBody @Valid GetEmbedWebUrlRequest request);
|
||||
|
||||
/**
|
||||
* 查询单位已启用的印章以及授权人员列表等等
|
||||
*/
|
||||
@PostMapping("api/ess/getOrgEnabledSeals")
|
||||
ApiResult<List<EssOrgAndSealInfo>> getOrgEnabledSeals(@RequestBody @Valid GetSealsRequest request);
|
||||
|
||||
/**
|
||||
* 查询印章管理员
|
||||
*/
|
||||
@PostMapping("api/ess/getSealPersons")
|
||||
ApiResult<List<EssSealPersonInfo>> getSealPersons(@RequestBody @Valid GetSealPersonRequest request);
|
||||
|
||||
/**
|
||||
* 添加印章人员
|
||||
*/
|
||||
@PostMapping("api/ess/addSealPerson")
|
||||
ApiResult<Boolean> addSealPerson(@RequestBody @Valid AddSealPersonRequest request);
|
||||
|
||||
/**
|
||||
* 删除印章人员
|
||||
*/
|
||||
@PostMapping("api/ess/removeSealPerson")
|
||||
ApiResult<Void> removeSealPerson(@RequestBody @Valid RemoveSealPersonRequest request);
|
||||
|
||||
/**
|
||||
* 单个人印章授权(去授权)
|
||||
*/
|
||||
@PostMapping("api/ess/addSealAuthorization")
|
||||
ApiResult<Void> addSealAuthorization(@RequestBody @Valid AddSealAuthorizationRequest request);
|
||||
|
||||
/**
|
||||
* 单个人印章取消授权
|
||||
*/
|
||||
@PostMapping("api/ess/removeSealAuthorization")
|
||||
ApiResult<Void> removeSealAuthorization(@RequestBody @Valid RemoveSealAuthorizationRequest request);
|
||||
|
||||
/**
|
||||
* 通过文件创建合同
|
||||
*/
|
||||
@PostMapping("api/ess/createContractByFile")
|
||||
ApiResult<CreateContractByFileResponse> createContractByFile(
|
||||
@RequestBody @Valid CreateContractByFileRequest request);
|
||||
|
||||
/**
|
||||
* 获取动态签署链接, 有效期为5分钟
|
||||
*/
|
||||
@PostMapping("api/ess/assignSignUrl")
|
||||
ApiResult<AssignSignUrlResponse> assignSignUrl(@RequestBody @Valid AssignSignUrlRequest request);
|
||||
|
||||
/**
|
||||
* 获取合同PDF文件地址. 下载链接有效期为5分钟
|
||||
*/
|
||||
@PostMapping("api/ess/getContractPDFUrl")
|
||||
ApiResult<DownloadSingedContractPdfResponse> getContractPDFUrl(
|
||||
@RequestBody @Valid DownloadSingedContractPdfRequest request);
|
||||
|
||||
/**
|
||||
* 从腾讯电子签下载合同PDF文件
|
||||
*/
|
||||
@PostMapping("api/ess/saveContractSnapshot")
|
||||
ApiResult<Void> saveContractSnapshot(@RequestBody @Valid SaveContractSnapshotRequest request);
|
||||
|
||||
/**
|
||||
* 撤销合同
|
||||
*/
|
||||
@PostMapping("api/ess/revokeContract")
|
||||
ApiResult<Void> revokeContract(@RequestBody @Valid RevokeContractRequest request);
|
||||
|
||||
/**
|
||||
* 获取合同详情, 通过合同id
|
||||
*/
|
||||
@PostMapping("api/ess/getContractByContractId")
|
||||
ApiResult<GetContractDetailByContractIdResponse> getContractByContractId(
|
||||
@RequestBody @Valid GetContractDetailByContractIdRequest request);
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api;
|
||||
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@EnableFeignClients("cn.axzo.nanopart.ess.api")
|
||||
public class EssAutoConfiguration {
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api;
|
||||
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.nanopart.ess.api.request.CallbackContent;
|
||||
import cn.axzo.nanopart.ess.api.request.CallbackRequest;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
|
||||
import javax.validation.Valid;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@FeignClient(name = "nanopart", url = "${axzo.service.nanopart:http://nanopart:8080}")
|
||||
public interface EssCallbackApi {
|
||||
|
||||
@PostMapping("api/ess/callback")
|
||||
ApiResult<Object> callback(@RequestBody @Valid CallbackRequest request);
|
||||
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
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,74 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
|
||||
import cn.axzo.nanopart.ess.api.enums.Constraint;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.validator.constraints.Range;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public abstract class CreateContractInfo {
|
||||
|
||||
/**
|
||||
* 合同名称
|
||||
*/
|
||||
@NotBlank(message = "contractName不能为空")
|
||||
private String contractName;
|
||||
|
||||
/**
|
||||
* 合同签署方
|
||||
*/
|
||||
@Valid
|
||||
@NotEmpty(message = "approvers不能为空")
|
||||
private List<Approver> approvers;
|
||||
|
||||
/**
|
||||
* 合同签署方的签署约束种类
|
||||
*/
|
||||
@NotNull(message = "approverConstraint不能为空")
|
||||
private Constraint constraint = Constraint.ONE_PERSON_PER_ORG;
|
||||
|
||||
/**
|
||||
* 签署方签署控件(印章/签名等)的生成方式.
|
||||
* 0: 在合同流程发起时,由发起人指定签署方的签署控件的位置和数量
|
||||
* 1: 签署方在签署时自行添加签署控件,可以拖动位置和控制数量
|
||||
*/
|
||||
@Range(min = 0, max = 1, message = "signBeanTag必须是0或1")
|
||||
private Long signBeanTag = 1L;
|
||||
|
||||
/**
|
||||
* 是否按 approvers 中指定的顺序进行签署
|
||||
*/
|
||||
private boolean signOrdered = false;
|
||||
|
||||
/**
|
||||
* 合同流程的签署截止时间,格式为Unix标准时间戳, 透传给腾讯电子签
|
||||
* 如果未设置签署截止时间,则默认为合同流程创建后的365天时截止
|
||||
* 如果在签署截止时间前未完成签署,则合同状态会变为已过期,导致合同作废。
|
||||
*/
|
||||
private Long deadlineMs;
|
||||
|
||||
@JsonIgnore
|
||||
public Set<Long> getApproverOuIds() {
|
||||
if (approvers == null)
|
||||
return Collections.emptySet();
|
||||
return approvers.stream().map(Approver::getOuId).collect(toSet());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class EssOrgAndSealInfo {
|
||||
|
||||
/**
|
||||
* 单位信息
|
||||
*/
|
||||
private EssOrgInfo org;
|
||||
|
||||
/**
|
||||
* 印章信息
|
||||
*/
|
||||
private List<EssSealInfo> seals = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class EssOrgInfo {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 单位名称
|
||||
*/
|
||||
private String ouName;
|
||||
|
||||
/**
|
||||
* 单位是否认证
|
||||
*/
|
||||
private boolean isOrgAuthorized;
|
||||
|
||||
/**
|
||||
* 超级管理员人员id
|
||||
*/
|
||||
private Long superAdminPersonId;
|
||||
|
||||
/**
|
||||
* 单位记录创建人id
|
||||
*/
|
||||
private Long createByPersonId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class EssSealInfo {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 印章在腾讯的id
|
||||
*/
|
||||
private String essSealId;
|
||||
|
||||
/**
|
||||
* 印章名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 印章类型. OFFICIAL: 公章, CONTRACT: 合同专用章, FINANCE: 财务专用章, PERSONNEL: 人事专用章, INVOICE: 发票专用章, LEGAL_PERSON_SEAL: 法定代表人章, OTHER: 其它
|
||||
*/
|
||||
private EssSealType type;
|
||||
|
||||
/**
|
||||
* 授权人员列表
|
||||
*/
|
||||
private List<EssSealPersonInfo> sealPersons = new ArrayList<>();
|
||||
|
||||
public void addSealPerson(EssSealPersonInfo person) {
|
||||
sealPersons.add(person);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,54 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class EssSealPersonInfo {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 印章用户信息
|
||||
*/
|
||||
private PersonProfileInfo sealPerson = new PersonProfileInfo();
|
||||
|
||||
/**
|
||||
* 印章授权人信息
|
||||
*/
|
||||
private PersonProfileInfo authorizedByPerson = new PersonProfileInfo();
|
||||
|
||||
/**
|
||||
* 印章id
|
||||
*/
|
||||
private String essSealId;
|
||||
|
||||
/**
|
||||
* 是否已经激活(实名认证)
|
||||
*/
|
||||
private boolean isPersonAuthorized;
|
||||
|
||||
/**
|
||||
* 授权时间, unix时间戳
|
||||
*/
|
||||
private Long authorizeTimeMs;
|
||||
|
||||
/**
|
||||
* 是否已经认证(印章授权)
|
||||
*/
|
||||
private boolean isSealAuthorized;
|
||||
|
||||
/**
|
||||
* 是否是超级管理员
|
||||
*/
|
||||
private boolean isSuperAdmin;
|
||||
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class OperatorInfo implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 发起方单位id
|
||||
*/
|
||||
@NotNull(message = "ouId不能为空")
|
||||
@Min(value = 1, message = "ouId必须大于0")
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 发起方人员id
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
@Min(value = 1, message = "personId必须大于0")
|
||||
private Long personId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.OrgPersonInfo;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public interface OrgPerson {
|
||||
|
||||
Long getOuId();
|
||||
|
||||
Long getPersonId();
|
||||
|
||||
default OrgPersonInfo toOrgPersonInfo() {
|
||||
OrgPersonInfo orgPersonInfo = new OrgPersonInfo();
|
||||
orgPersonInfo.setOuId(getOuId());
|
||||
orgPersonInfo.setPersonId(getPersonId());
|
||||
return orgPersonInfo;
|
||||
}
|
||||
|
||||
static boolean equals(OrgPerson a, OrgPerson b) {
|
||||
return Objects.equals(a.getOuId(), b.getOuId()) && Objects.equals(a.getPersonId(), b.getPersonId());
|
||||
}
|
||||
|
||||
static String toString(OrgPerson person) {
|
||||
return String.format("%d_%d", person.getOuId(), person.getPersonId());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class OrgPersons<T extends OrgPerson> {
|
||||
|
||||
private final Collection<T> persons;
|
||||
|
||||
public static <T extends OrgPerson> OrgPersons<T> wrap(Collection<T> persons) {
|
||||
return new OrgPersons<>(persons);
|
||||
}
|
||||
|
||||
public Optional<T> findByPerson(OrgPerson person) {
|
||||
return persons.stream().filter(p -> Objects.equals(p.getOuId(), person.getOuId())
|
||||
&& Objects.equals(p.getPersonId(), person.getPersonId())).findFirst();
|
||||
}
|
||||
|
||||
public Optional<T> findByOrgId(Long ouId) {
|
||||
return persons.stream().filter(p -> Objects.equals(p.getOuId(), ouId)).findFirst();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class PersonProfileInfo {
|
||||
|
||||
/**
|
||||
* 自然人id
|
||||
*/
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 姓名
|
||||
*/
|
||||
private String personName;
|
||||
|
||||
/**
|
||||
* 头像
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
}
|
||||
@ -0,0 +1,95 @@
|
||||
|
||||
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;
|
||||
import org.hibernate.validator.constraints.Range;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class Approver implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 签署方人员信息, 如果是动态签署人, 则传null, 在获取签署链接时再指定签署人
|
||||
*/
|
||||
@Valid
|
||||
private OrgPersonInfo signPerson;
|
||||
|
||||
/**
|
||||
* 签署选项
|
||||
*/
|
||||
private SignOption signOption = new SignOption();
|
||||
|
||||
/**
|
||||
* 在指定签署方时,可选择企业B端或个人C端等不同的参与者类型
|
||||
*/
|
||||
@NotNull(message = "approverType不能为空")
|
||||
private EssApproverType approverType = EssApproverType.ORGANIZATION;
|
||||
|
||||
/**
|
||||
* 签署方在签署合同之前,需要强制阅读合同的时长,可指定为3秒至300秒之间的任意值
|
||||
*/
|
||||
@Range(min = 3, max = 300, message = "preReadTime必须在3-300之间")
|
||||
@NotNull(message = "preReadTime不能为空")
|
||||
private Long preReadTimeSeconds = 5L;
|
||||
|
||||
/**
|
||||
* 指定盖章时, 使用的章类型
|
||||
*/
|
||||
private List<EssSealType> sealTypes;
|
||||
|
||||
/**
|
||||
* 扩展信息, 内部使用
|
||||
*/
|
||||
private JSONObject internal;
|
||||
|
||||
public void setEssRecipientId(String essRecipientId) {
|
||||
getOrCreateExtension().put("essRecipientId", essRecipientId);
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public String getEssRecipientId() {
|
||||
if (internal == null)
|
||||
return null;
|
||||
return internal.getString("essRecipientId");
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public JSONObject getOrCreateExtension() {
|
||||
if (internal == null)
|
||||
internal = new JSONObject();
|
||||
return internal;
|
||||
}
|
||||
|
||||
public boolean isSignPersonPreset() {
|
||||
return signPerson != null;
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public Long getOuId() {
|
||||
return signPerson == null ? 0L : signPerson.getOuId();
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public Long getPersonId() {
|
||||
return signPerson == null ? 0L : signPerson.getPersonId();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain.contract;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractApproveState;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class EssApproveDetail {
|
||||
|
||||
/**
|
||||
* 签署人, 动态签署人在没有签署(state=PENDING)的时候可能为null
|
||||
*/
|
||||
private OrgPersonInfo signPerson;
|
||||
|
||||
/**
|
||||
* 签署编号
|
||||
*/
|
||||
private String recipientId;
|
||||
|
||||
/**
|
||||
* 签署状态
|
||||
*/
|
||||
private EssContractApproveState state;
|
||||
|
||||
/**
|
||||
* 签署顺序
|
||||
*/
|
||||
private long signOrder;
|
||||
|
||||
/**
|
||||
* 对应签署人签署此合同的时间
|
||||
*/
|
||||
private long approveTimeMs;
|
||||
|
||||
/**
|
||||
* 对应签署人状态的简单描述, 如: 已签署或者拒签的原因等
|
||||
*/
|
||||
private String message;
|
||||
|
||||
/**
|
||||
* 对应签署人的签署截止时间
|
||||
*/
|
||||
private long approverDeadlineMs;
|
||||
|
||||
/**
|
||||
* 单位id, 动态签署人在没有签署(state=PENDING)的时候可能为空
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 单位名称, 动态签署人在没有签署(state=PENDING)的时候可能为空
|
||||
*/
|
||||
private String ouName;
|
||||
|
||||
/**
|
||||
* 对应签署人的手机号, 动态签署人在没有签署(state=PENDING)的时候可能为空
|
||||
*/
|
||||
private String phoneNumber;
|
||||
}
|
||||
@ -0,0 +1,73 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain.contract;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractState;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class EssContractInfo {
|
||||
|
||||
/**
|
||||
* 发起合同的应用或业务场景
|
||||
*/
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 业务编码
|
||||
*/
|
||||
private String bizCode;
|
||||
|
||||
/**
|
||||
* 幂等编码
|
||||
*/
|
||||
private String idempotentCode;
|
||||
|
||||
/**
|
||||
* 合同发起方单位id
|
||||
*/
|
||||
private Long creatorOuId;
|
||||
|
||||
/**
|
||||
* 合同发起方人员id
|
||||
*/
|
||||
private Long creatorPersonId;
|
||||
|
||||
/**
|
||||
* 合同名称
|
||||
*/
|
||||
private String contractName;
|
||||
|
||||
/**
|
||||
* 电子签那边的合同id
|
||||
*/
|
||||
private String essContractId;
|
||||
|
||||
/**
|
||||
* 合同状态. INIT: 合同创建, PART: 合同签署中, ALL: 合同签署完成, REJECT: 合同拒签, CANCEL: 合同撤回, WILLEXPIRE: 合同即将过期, DEADLINE: 合同流签(合同过期), RELIEVED: 解除协议(已解除), INVALID: 合同已失效, EXCEPTION: 合同异常
|
||||
*/
|
||||
private EssContractState state;
|
||||
|
||||
/**
|
||||
* 合并签署方信息, 如果是动态签署, 里面的签署人信息可能为nul
|
||||
*/
|
||||
private List<Approver> approvers;
|
||||
|
||||
/**
|
||||
* 合同的签署方的签署情况
|
||||
* <p/>
|
||||
* 每次腾讯的回调都是给的全量签署情况数据, 如果业务依赖签署情况推荐业务状态, 需要自行做幂等处理
|
||||
*/
|
||||
private List<EssApproveDetail> approveDetails;
|
||||
|
||||
/**
|
||||
* 腾讯电子签那边的消息
|
||||
*/
|
||||
private String essMessage;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain.contract;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.springframework.web.context.request.async.StandardServletAsyncWebRequest;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class OrgPersonInfo implements OrgPerson {
|
||||
|
||||
public static OrgPersonInfo create(OrgPerson person) {
|
||||
return create(person.getOuId(), person.getPersonId());
|
||||
}
|
||||
|
||||
public static OrgPersonInfo create(Long ouId, Long personId) {
|
||||
OrgPersonInfo orgPersonInfo = new OrgPersonInfo();
|
||||
orgPersonInfo.setOuId(ouId);
|
||||
orgPersonInfo.setPersonId(personId);
|
||||
return orgPersonInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@NotNull(message = "ouId不能为空")
|
||||
@Min(value = 1, message = "ouId必须大于0")
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 人员id
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
@Min(value = 1, message = "personId必须大于0")
|
||||
private Long personId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,26 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.domain.contract;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* <a href="https://qian.tencent.com/developers/partnerApis/dataTypes/#approveroption">签署选项</a>
|
||||
*
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class SignOption {
|
||||
|
||||
/**
|
||||
* 是否可以拒签. false-可以拒签, true-不可以拒签
|
||||
*/
|
||||
private boolean noRefuse = true;
|
||||
|
||||
/**
|
||||
* 是否可以转发. false-可以转发 true-不可以转发
|
||||
*/
|
||||
private boolean noTransfer = false;
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public enum Constraint {
|
||||
|
||||
// 一个子客只允许一个用户盖章
|
||||
ONE_PERSON_PER_ORG
|
||||
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public enum EssApproverType {
|
||||
// 企业/ 企业员工
|
||||
ORGANIZATION,
|
||||
// 企业/ 企业员工自动签
|
||||
ENTERPRISESERVER
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum EssConsoleUrlEndpoint {
|
||||
|
||||
PC("PC", "(默认)web控制台链接, 需要在PC浏览器中打开"),
|
||||
CHANNEL("CHANNEL", "H5跳转到电子签小程序链接, 一般用于发送短信中带的链接, 打开后进入腾讯电子签小程序"),
|
||||
SHORT_URL("SHORT_URL", "H5跳转到电子签小程序链接的短链形式, 一般用于发送短信中带的链接, 打开后进入腾讯电子签小程序"),
|
||||
WEIXIN_QRCODE_URL("WEIXIN_QRCODE_URL", "直接跳转至电子签小程序的二维码链接,无需通过中转页。您需要自行将其转换为二维码,使用微信扫码后可直接进入。请注意,直接点击链接是无效的。"),
|
||||
APP("APP", "APP或小程序跳转电子签小程序链接, 一般用于贵方小程序或者APP跳转过来, 打开后进入腾讯电子签小程序"),
|
||||
H5("H5", "H5长链接跳转H5链接, 一般用于贵方H5跳转过来, 打开后进入腾讯电子签H5页面"),
|
||||
SHORT_H5("SHORT_H5", "H5短链跳转H5的短链形式, 一般用于发送短信中带的链接, 打开后进入腾讯电子签H5页面")
|
||||
|
||||
;
|
||||
|
||||
private final String code;
|
||||
private final String description;
|
||||
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public enum EssContractApproveState {
|
||||
|
||||
PENDING("待签署"),
|
||||
ACCEPT("已签署"),
|
||||
REJECT("拒绝"),
|
||||
DEADLINE("过期没人处理"),
|
||||
CANCEL("流程已撤回"),
|
||||
STOP("流程已终止"),
|
||||
WAITPICKUP("待领取"),
|
||||
FILLPENDING("待填写"),
|
||||
FILLACCEPT("填写完成"),
|
||||
FORWARD("已转他人处理"),
|
||||
RELIEVED("解除协议(已解除)"),
|
||||
FILLREJECT("拒绝填写"),
|
||||
EXCEPTION("异常");
|
||||
|
||||
private final String description;
|
||||
|
||||
public static EssContractApproveState fromEssCode(String code) {
|
||||
for (EssContractApproveState value : values()) {
|
||||
if (value.name().equalsIgnoreCase(code)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,42 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public enum EssContractState {
|
||||
|
||||
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()) {
|
||||
if (value.name().equalsIgnoreCase(code)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@Accessors(fluent = true)
|
||||
@RequiredArgsConstructor
|
||||
public enum EssEmbedType {
|
||||
|
||||
// 生成创建印章的嵌入页面
|
||||
CREATE_SEAL(false, "CREATE_SEAL", EssSubject.SEAL),
|
||||
// 生成预览印章列表的嵌入页面
|
||||
PREVIEW_SEAL_LIST(false, "PREVIEW_SEAL_LIST", EssSubject.SEAL),
|
||||
// 生成预览印章详情的嵌入页面
|
||||
PREVIEW_SEAL_DETAIL(true, "PREVIEW_SEAL_DETAIL", EssSubject.SEAL),
|
||||
// 生成预览合同文档的嵌入页面(H5链接,支持移动端的浏览器中打开)
|
||||
PREVIEW_CONTRACT(true, "PREVIEW_FLOW", EssSubject.CONTRACT),
|
||||
// 生成预览合同详情的嵌入页面(仅支持PC的浏览器中打开)
|
||||
PREVIEW_CONTRACT_DETAIL(true, "PREVIEW_FLOW_DETAIL", EssSubject.CONTRACT);
|
||||
|
||||
private final boolean businessIdRequired;
|
||||
private final String essCode;
|
||||
private final EssSubject essSubject;
|
||||
|
||||
public enum EssSubject {
|
||||
SEAL, CONTRACT
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public enum EssPersonState {
|
||||
// 创建
|
||||
CREATED,
|
||||
// 认证
|
||||
AUTHORIZED,
|
||||
// 离职
|
||||
RESIGNED
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum EssSealState {
|
||||
// 创建
|
||||
CREATE,
|
||||
// 删除
|
||||
DELETED,
|
||||
// 停用
|
||||
DISABLED,
|
||||
// 启用
|
||||
ENABLED;
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* <a href="https://qian.tencent.com/developers/partnerApis/seals/ChannelDescribeOrganizationSeals/">印章类型</a>
|
||||
*
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
public enum EssSealType {
|
||||
|
||||
OFFICIAL("公章", "OFFICIAL", "OFFICIAL"),
|
||||
CONTRACT("合同专用章", "CONTRACT", "CONTRACT"),
|
||||
FINANCE("财务专用章", "FINANCE", "FINANCE"),
|
||||
PERSONNEL("人事专用章", "PERSONNEL", "PERSONNEL"),
|
||||
OTHER("其他", "OTHER");
|
||||
|
||||
private final String description;
|
||||
private final String useForLimitCode;
|
||||
private final String[] essCodes;
|
||||
|
||||
EssSealType(String description, String useForLimitCode, String... essCodes) {
|
||||
this.description = description;
|
||||
this.useForLimitCode = useForLimitCode;
|
||||
this.essCodes = essCodes;
|
||||
}
|
||||
|
||||
public static EssSealType fromEssCode(String essCode) {
|
||||
for (EssSealType value : values()) {
|
||||
for (String code : value.essCodes) {
|
||||
if (code.equals(essCode)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return OTHER;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,35 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @Author zr
|
||||
* @Date 2024/3/19 18:01
|
||||
* @Description
|
||||
**/
|
||||
@Getter
|
||||
public enum MQEvent {
|
||||
|
||||
ESS_CONTRACT_STATE_CHANGE("nanopart", "ess-contract-state-change", "腾讯电子签合同状态变化"),
|
||||
|
||||
;
|
||||
private final String model;
|
||||
private final String tag;
|
||||
private final String desc;
|
||||
private final Event.EventCode eventCode;
|
||||
|
||||
MQEvent(String model, String tag, String desc) {
|
||||
this.eventCode = Event.EventCode.builder().module(model).name(tag).build();
|
||||
this.model = model;
|
||||
this.tag = tag;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public static MQEvent getByName(String name) {
|
||||
return Arrays.stream(MQEvent.values()).filter(item -> item.name().equals(name)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public enum SignUrlEndpoint {
|
||||
PC, WEIXIN_APP
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
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 EssContractStateChangeMessage extends MqMessage {
|
||||
|
||||
/**
|
||||
* 合同信息, 处理签署详情时需要做幂等
|
||||
*/
|
||||
private EssContractInfo contract;
|
||||
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.mq;
|
||||
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public abstract class MqMessage implements Serializable {
|
||||
|
||||
/**
|
||||
* 消息唯一id
|
||||
*/
|
||||
private String messageId = UUID.randomUUID().toString();
|
||||
|
||||
/**
|
||||
* 消息发送时间
|
||||
*/
|
||||
private Date messageSendTime = new Date();
|
||||
|
||||
/**
|
||||
* 消息发送时间, 字符串格式
|
||||
*/
|
||||
private String messageSendTimeStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(messageSendTime);
|
||||
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AddSealAuthorizationRequest implements SealAndPersonRequest {
|
||||
|
||||
/**
|
||||
* 印章id
|
||||
*/
|
||||
@NotBlank(message = "essSealId不能为空")
|
||||
private String essSealId;
|
||||
|
||||
/**
|
||||
* 人员id
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 前端忽略, yoke传递
|
||||
*/
|
||||
private Long operatorPersonId;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AddSealPersonRequest {
|
||||
|
||||
/**
|
||||
* 印章id
|
||||
*/
|
||||
@NotBlank(message = "essSealId不能为空")
|
||||
private String essSealId;
|
||||
|
||||
/**
|
||||
* 人员id列表
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 前端忽略, yoke传递
|
||||
*/
|
||||
private Long operatorPersonId;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,55 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AssignSignUrlRequest implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 合同id
|
||||
*/
|
||||
@NotBlank(message = "essContractId不能为空")
|
||||
private String essContractId;
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@NotNull(message = "ouId不能为空")
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 人员id, 需要有印章权限
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* PC: 电脑端, WEIXIN_APP: 小程序, H5: h5
|
||||
*/
|
||||
@NotNull(message = "endpoint不能为空")
|
||||
private SignUrlEndpoint endpoint;
|
||||
|
||||
/**
|
||||
* 签署方编号, 可以使用该编号指定动态签署方的信息, 该编号在创建合同的时候会返回
|
||||
*/
|
||||
@NotBlank(message = "recipientId不能为空")
|
||||
private String recipientId;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CallbackContent {
|
||||
private String encrypt;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,215 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CallbackRequest {
|
||||
|
||||
@JsonProperty(value = "MsgId")
|
||||
@JSONField(name = "MsgId")
|
||||
private String MsgId;
|
||||
@JsonProperty(value = "MsgType")
|
||||
@JSONField(name = "MsgType")
|
||||
private String MsgType;
|
||||
@JsonProperty(value = "MsgVersion")
|
||||
@JSONField(name = "MsgVersion")
|
||||
private String MsgVersion;
|
||||
@JsonProperty(value = "MsgData")
|
||||
@JSONField(name = "MsgData")
|
||||
private JSONObject MsgData;
|
||||
|
||||
public <T> T readMsgData(Class<T> clazz) {
|
||||
return MsgData.toJavaObject(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class OrgAuthorizationFinish {
|
||||
// 第三方应用的应用编号
|
||||
private String ApplicationId;
|
||||
// 第三方平台子客企业的唯一标识,定义Agent中的ProxyOrganizationOpenId一样
|
||||
private String ProxyOrganizationOpenId;
|
||||
// 开通服务的第三方平台子客企业员工的唯一标识
|
||||
private String ProxyOperatorOpenId;
|
||||
// 子企业的ProxyAppId, 现在还没有地方使用此ProxyAppId, 可忽略
|
||||
private String ProxyAppId;
|
||||
// 是否开通, true表示开通, false表示未开通
|
||||
private boolean OpenSuccess;
|
||||
// 子企业的企业名字
|
||||
private String OrganizationName;
|
||||
// 子企业的企业社会统一信用代码
|
||||
private String USCC;
|
||||
// 子企业的法人的姓名
|
||||
private String LegalName;
|
||||
// 子企业的法人的OpenId
|
||||
private String LegalOpenId;
|
||||
// 子企业超管的姓名
|
||||
private String AdminName;
|
||||
// 子企业超管的手机号(打码)
|
||||
private String AdminMobile;
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class OrgPersonJoin {
|
||||
// 第三方应用的应用编号
|
||||
private String ApplicationId;
|
||||
// 第三方平台子客企业的唯一标识,定义Agent中的ProxyOrganizationOpenId一样, 可以参考Agent结构体
|
||||
private String ProxyOrganizationOpenId;
|
||||
// 加入企业的第三方平台子客企业员工的唯一标识
|
||||
private String ProxyOperatorOpenId;
|
||||
// 员工姓名
|
||||
private String EmployeeName;
|
||||
// 员工手机号(打码)
|
||||
private String EmployeeMobile;
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class SealOperate {
|
||||
// 第三方应用的应用编号
|
||||
private String ApplicationId;
|
||||
// 第三方平台子客企业的唯一标识
|
||||
private String ProxyOrganizationOpenId;
|
||||
// 执行对应印章动作的第三方平台子客企业员工的唯一标识
|
||||
private String ProxyOperatorOpenId;
|
||||
/**
|
||||
* 1. 如果印章授权给员工的行为, 此处为被授权员工的OpenId
|
||||
* 2. 如果是取消某员工的印章授权, 此处为被取消授权员工的OpenId
|
||||
* 3. 其他印章行为没有此字段
|
||||
*/
|
||||
private String AuthorizedOperatorOpenId;
|
||||
// 对应的印章ID,为32位字符串
|
||||
private String SealId;
|
||||
/**
|
||||
* 对应的印章类型, 类型的值包括:
|
||||
* OFFICIAL:企业公章
|
||||
* CONTRACT:企业合同专用章
|
||||
* ORGANIZATION_SEAL:客户本地上传的企业印章
|
||||
* LEGAL_PERSON_SEAL:客户本地上传的法人印章
|
||||
* FINANCE:财务专用章
|
||||
* PERSONNEL:人事专用章
|
||||
*/
|
||||
private String SealType;
|
||||
/**
|
||||
* 印章创建 Create
|
||||
* 印章删除 Delete
|
||||
* 印章停用 Disable
|
||||
* 印章启用 Enable
|
||||
* 印章授权给某些员工 Valid
|
||||
* 取消某些员工的印章授权 Invalid
|
||||
*/
|
||||
private String Operate;
|
||||
/**
|
||||
* 1. 如果印章启用或者停用行为, 是此印章权限的员工们的OpenId
|
||||
* 2. 其他印章行为没有此字段
|
||||
*/
|
||||
private JSONArray AuthorizedUsers;
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class ContractStateChanged {
|
||||
// 第三方平台子客企业的唯一标识
|
||||
private String ApplicationId;
|
||||
// 第三方平台子客企业的唯一标识
|
||||
private String ProxyOrganizationOpenId;
|
||||
// 第三方平台子客企业员工的唯一标识
|
||||
private String ProxyOperatorOpenId;
|
||||
// 用PDF文件创建签署流程和用模板创建签署流程创建签署流程时候传递的CustomerData参数
|
||||
private String CustomerData;
|
||||
// 触发回调的合同流程ID,为32位字符串
|
||||
private String FlowId;
|
||||
// 触发回调的合同流程的名称
|
||||
private String FlowName;
|
||||
// 触发回调的合同流程的类别分类
|
||||
private String FlowType;
|
||||
// 合同状态,具体含义可以参考上述其他说明中的 会出现回调的合同状态
|
||||
private String FlowStatus;
|
||||
// 当合同流程状态为合同拒签, 合同撤回等状态时,此字段为拒签或撤销原因,其他状态时此字段为空值
|
||||
private String FlowMessage;
|
||||
// 合同流程的创建时间戳,格式为Unix标准时间戳(秒)
|
||||
private Integer CreateOn;
|
||||
// 签署流程的签署截止时间,格式为Unix标准时间戳(秒)
|
||||
private Integer Deadline;
|
||||
// 合同(流程)关注方信息列表, 结构体定义可以查看开发者中的CcInfo
|
||||
private JSONArray CcInfo;
|
||||
// 合同(流程)签署人信息列表, 结构体的定义可以参考下面的FlowApproverDetail
|
||||
private List<FlowApproverDetail> FlowApproverInfo;
|
||||
// 如果合同归属合同组, 此结构体为合同组的信息, 结构体的定义可以参考下面的FlowGroupMessageDetail
|
||||
private JSONObject FlowGroupMessage;
|
||||
// 此回调触发的时间,格式为Unix标准时间戳(秒)
|
||||
private Integer OccurTime;
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class FlowApproverDetail {
|
||||
// 如果第三方子企业员工签署, 此字段为第三方子企业员工的唯一标识
|
||||
private String ProxyOperatorOpenId;
|
||||
// 如果第三方子企业员工签署, 此字段为第三方子企业的名称
|
||||
private String ProxyOrganizationName;
|
||||
// 如果saas企业员工签署, 此字段为saas企业的名称
|
||||
private String OrganizationName;
|
||||
// 如果第三方子企业员工签署, 此字段为第三方子企业的唯一标识
|
||||
private String ProxyOrganizationOpenId;
|
||||
// 对应签署人的手机号
|
||||
private String PhoneNumber;
|
||||
// 如果合同是顺序签署, SignOrder对应签署人的签署顺序
|
||||
private long SignOrder;
|
||||
// 对应签署人的参与角色ID
|
||||
private String RecipientId;
|
||||
// 对应签署人的名字
|
||||
private String ApproveName;
|
||||
// 对应签署人的状态, 具体含义可以参考上述其他说明中的 签署人状态
|
||||
private String ApproveStatus;
|
||||
// 对应签署人状态的简单描述, 如: 已签署或者拒签的原因等
|
||||
private String ApproveMessage;
|
||||
// 对应签署人签署此合同的时间,格式为Unix标准时间戳(秒)
|
||||
private long ApproveTime;
|
||||
// 对应签署人签署此合同的证书信息, 此功能为白名单功能, 使用前请联系对接的客户经理沟通
|
||||
private String CaSign;
|
||||
// 对应签署人的签署截止时间,格式为Unix标准时间戳(秒)
|
||||
private long ApproverDeadline;
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class SuperAdminChanged {
|
||||
// 第三方应用的应用编号
|
||||
private String ApplicationId;
|
||||
// 第三方平台子客企业的唯一标识
|
||||
private String ProxyOrganizationOpenId;
|
||||
// 新的超管的企业的第三方平台子客企业员工的唯一标识
|
||||
private String ChangeToUserOpenId;
|
||||
// 新的超管的名字
|
||||
private String ChangeToUserName;
|
||||
// 新的超管的手机号
|
||||
private String ChangeToUserMobile;
|
||||
// 老的超管的企业的第三方平台子客企业员工的唯一标识
|
||||
private String OldAdminOpenId;
|
||||
// 老的超管的名字
|
||||
private String OldAdminName;
|
||||
// 老的超管的手机号
|
||||
private String OldAdminMobile;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssConsoleUrlEndpoint;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CreateConsoleLoginUrlRequest implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@NotNull(message = "单位id不能为空")
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 人员id
|
||||
*/
|
||||
@NotNull(message = "人员id不能为空")
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 具体传啥问产品:
|
||||
* PC: (默认)web控制台链接, 需要在PC浏览器中打开
|
||||
* CHANNEL: H5跳转到电子签小程序链接, 一般用于发送短信中带的链接, 打开后进入腾讯电子签小程序
|
||||
* SHORT_URL: H5跳转到电子签小程序链接的短链形式, 一般用于发送短信中带的链接, 打开后进入腾讯电子签小程序
|
||||
* WEIXIN_QRCODE_URL: 直接跳转至电子签小程序的二维码链接,无需通过中转页。您需要自行将其转换为二维码,使用微信扫码后可直接进入。请注意,直接点击链接是无效的。
|
||||
* APP: APP或小程序跳转电子签小程序链接, 一般用于贵方小程序或者APP跳转过来, 打开后进入腾讯电子签小程序
|
||||
* H5: H5长链接跳转H5链接, 一般用于贵方H5跳转过来, 打开后进入腾讯电子签H5页面
|
||||
* SHORT_H5: H5短链跳转H5的短链形式, 一般用于发送短信中带的链接, 打开后进入腾讯电子签H5页面
|
||||
*/
|
||||
@NotNull(message = "endpoint不能为空")
|
||||
private EssConsoleUrlEndpoint endpoint;
|
||||
|
||||
/**
|
||||
* 调试参数, 不填
|
||||
*/
|
||||
private transient boolean essCheckLoginPerson = true;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.CreateContractByFile;
|
||||
import cn.axzo.nanopart.ess.api.domain.CreateContractInfo;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CreateContractByFileRequest extends CreateContractRequest {
|
||||
|
||||
/**
|
||||
* 通过上传PDF发起合同
|
||||
*/
|
||||
@Valid
|
||||
@NotNull(message = "byFile不能为空")
|
||||
private CreateContractByFile byFile;
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public CreateContractInfo getContract() {
|
||||
return byFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.CreateContractInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.OperatorInfo;
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
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.NotNull;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public abstract class CreateContractRequest {
|
||||
|
||||
/**
|
||||
* 发起合同的应用或业务场景
|
||||
*/
|
||||
@NotBlank(message = "appCode不能为空")
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 业务编码
|
||||
*/
|
||||
@NotNull(message = "bizCode不能为空")
|
||||
private String bizCode;
|
||||
|
||||
/**
|
||||
* 幂等编码, 最大长度200. 使用appCode和idempotentCode的合同不能重复
|
||||
*/
|
||||
@NotBlank(message = "idempotentCode不能为空")
|
||||
private String idempotentCode = UUID.randomUUID().toString();
|
||||
|
||||
/**
|
||||
* 合同发起方信息
|
||||
*/
|
||||
@Valid
|
||||
@NotNull(message = "creator不能为空")
|
||||
private OperatorInfo creator;
|
||||
|
||||
@JsonIgnore
|
||||
@JSONField(serialize = false)
|
||||
public abstract CreateContractInfo getContract();
|
||||
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class DownloadSingedContractPdfRequest {
|
||||
|
||||
/**
|
||||
* 合同id
|
||||
*/
|
||||
@NotBlank(message = "essContractId不能为空")
|
||||
private String essContractId;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetContractDetailByContractIdRequest {
|
||||
|
||||
/**
|
||||
* 合同id
|
||||
*/
|
||||
@NotBlank(message = "essContractId不能为空")
|
||||
private String essContractId;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,43 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetContractSignUrlRequest implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 合同id
|
||||
*/
|
||||
@NotBlank(message = "essContractId不能为空")
|
||||
private String essContractId;
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@NotNull(message = "ouId不能为空")
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 人员id, 需要有印章权限
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* PC: 电脑端, WEIXIN_APP: 小程序
|
||||
*/
|
||||
@NotNull(message = "urlType不能为空")
|
||||
private SignUrlEndpoint urlType;
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.EssEmbedType;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetEmbedWebUrlRequest {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@NotNull(message = "单位id不能为空")
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 内嵌类型.
|
||||
* CREATE_SEAL: 生成创建印章的嵌入页面
|
||||
* PREVIEW_CONTRACT: 生成预览合同文档的嵌入页面(H5链接,支持移动端的浏览器中打开)
|
||||
* PREVIEW_CONTRACT_DETAIL: 生成预览合同详情的嵌入页面(仅支持PC的浏览器中打开)
|
||||
* PREVIEW_SEAL_LIST: 生成预览印章列表的嵌入页面
|
||||
* PREVIEW_SEAL_DETAIL: 生成预览印章详情的嵌入页面
|
||||
*/
|
||||
@NotNull(message = "内嵌类型不能为空")
|
||||
private EssEmbedType embedType;
|
||||
|
||||
/**
|
||||
* 业务id.
|
||||
* PREVIEW_CONTRACT: 传入合同id
|
||||
* PREVIEW_CONTRACT_DETAIL: 传入合同id
|
||||
* PREVIEW_SEAL_DETAIL: 传入印章id
|
||||
*/
|
||||
private String businessId;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotEmpty;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetOrgAuthStatesRequest {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@NotEmpty(message = "单位id不能为空")
|
||||
private Set<Long> ouIds;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetPersonAuthStateRequest implements OrgPerson {
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
@NotNull(message = "单位id不能为空")
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 人员id
|
||||
*/
|
||||
@NotNull(message = "人员id不能为空")
|
||||
private Long personId;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetSealPersonRequest {
|
||||
|
||||
/**
|
||||
* 印章在腾讯的id
|
||||
*/
|
||||
@NotBlank(message = "essSealId不能为空")
|
||||
private String essSealId;
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetSealsRequest {
|
||||
|
||||
/**
|
||||
* 单位列表
|
||||
*/
|
||||
@NotNull(message = "单位列表不能为空")
|
||||
private Set<Long> ouIds;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class RemoveSealAuthorizationRequest implements SealAndPersonRequest {
|
||||
|
||||
/**
|
||||
* 印章id
|
||||
*/
|
||||
@NotBlank(message = "essSealId不能为空")
|
||||
private String essSealId;
|
||||
|
||||
/**
|
||||
* 人员id
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
private Long personId;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class RemoveSealPersonRequest {
|
||||
|
||||
/**
|
||||
* 印章id
|
||||
*/
|
||||
@NotBlank(message = "essSealId不能为空")
|
||||
private String essSealId;
|
||||
|
||||
/**
|
||||
* 人员id
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
private Long personId;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,32 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
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;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class SaveContractSnapshotRequest {
|
||||
|
||||
/**
|
||||
* 合同id
|
||||
*/
|
||||
@NotBlank(message = "essContractId不能为空")
|
||||
private String essContractId;
|
||||
|
||||
/**
|
||||
* 是否重复下载, 即已经下载过了, 但是需要重新下载.
|
||||
* 如果合同已经是终状 retryDownload=true 也不会重新下载
|
||||
*/
|
||||
private boolean retryDownload = false;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public interface SealAndPersonRequest {
|
||||
|
||||
String getEssSealId();
|
||||
|
||||
Long getPersonId();
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AssignSignUrlResponse {
|
||||
|
||||
/**
|
||||
* 有效期为5分钟.
|
||||
*/
|
||||
private String url;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CreateConsoleLoginUrlResponse {
|
||||
|
||||
/**
|
||||
* 腾讯电子签登录地址
|
||||
*/
|
||||
private String consoleLoginUrl;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,40 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CreateContractByFileResponse {
|
||||
|
||||
/**
|
||||
* 合同id
|
||||
*/
|
||||
private String essContractId;
|
||||
|
||||
/**
|
||||
* 签署方编号, 可以使用该编号指定动态签署方的信息, 顺序和请求中的approvers一致.
|
||||
* <p/>
|
||||
* 比如在使用了动态签署人的情况下, 就需要保存这个字段
|
||||
* <p/>
|
||||
* 在获取签署链接的时候回传到获取签署链接的请求中, 用以和创建合同的请求中的签署人的其它信息进行匹配
|
||||
*/
|
||||
private List<String> essRecipientIds;
|
||||
|
||||
/**
|
||||
* 是否重复 (幂等)
|
||||
*/
|
||||
private boolean isDuplicate;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class DownloadSingedContractPdfResponse {
|
||||
|
||||
/**
|
||||
* 合同pdf下载地址. 下载链接有效期为5分钟
|
||||
*/
|
||||
private String pdfUrl;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.EssContractInfo;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetContractDetailByContractIdResponse {
|
||||
|
||||
/**
|
||||
* 合同信息
|
||||
*/
|
||||
private EssContractInfo contract;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetContractSignUrlResponse {
|
||||
|
||||
/**
|
||||
* 签署地址或二维码地址, 有效期为5分钟
|
||||
* 如果是PC端, 才是二维码地址
|
||||
* 如果是小程序端, 则是小程序地址
|
||||
*/
|
||||
private String signOrQrUrl;
|
||||
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetEmbedWebUrlResponse {
|
||||
|
||||
/**
|
||||
* 内嵌页面地址, 有效期为5分钟
|
||||
*/
|
||||
private String embedWebUrl;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,29 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetOrgAuthStatesResponse {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 是否开通了电子签
|
||||
*/
|
||||
private boolean isAuthorized;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class GetPersonAuthStateResponse {
|
||||
|
||||
/**
|
||||
* 是否认证
|
||||
*/
|
||||
private boolean isAuthorized;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.api.utils;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public enum YesOrNo {
|
||||
YES("YES", "是"), NO("NO", "是");
|
||||
|
||||
private final String code;
|
||||
private final String desc;
|
||||
|
||||
public static YesOrNo valueOf(boolean value) {
|
||||
return value ? YES : NO;
|
||||
}
|
||||
|
||||
public boolean booleanValue() {
|
||||
return this == YES;
|
||||
}
|
||||
|
||||
public boolean isYes() {
|
||||
return this == YES;
|
||||
}
|
||||
|
||||
public boolean isNo() {
|
||||
return this == NO;
|
||||
}
|
||||
}
|
||||
2
ess/ess-api/src/main/resources/META-INF/spring.factories
Normal file
2
ess/ess-api/src/main/resources/META-INF/spring.factories
Normal file
@ -0,0 +1,2 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.axzo.nanopart.ess.api.EssAutoConfiguration
|
||||
128
ess/ess-server/pom.xml
Normal file
128
ess/ess-server/pom.xml
Normal file
@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<artifactId>ess</artifactId>
|
||||
<version>${revision}</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>ess-server</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>ess-server</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.xuxueli</groupId>
|
||||
<artifactId>xxl-job-core</artifactId>
|
||||
<version>2.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.tencentcloudapi</groupId>
|
||||
<artifactId>tencentcloud-sdk-java</artifactId>
|
||||
<version>3.1.1210</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-web-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-spring-cloud-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-consumer-spring-cloud-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-processor-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!--mybatis-plus-->
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-mybatisplus-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!-- swagger-yapi -->
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-swagger-yapi-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework</groupId>
|
||||
<artifactId>axzo-logger-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.framework.rocketmq</groupId>
|
||||
<artifactId>axzo-common-rocketmq</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.pokonyan</groupId>
|
||||
<artifactId>pokonyan</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.workflow</groupId>
|
||||
<artifactId>workflow-engine-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.maokai</groupId>
|
||||
<artifactId>maokai-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.nanopart</groupId>
|
||||
<artifactId>ess-api</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.basics</groupId>
|
||||
<artifactId>basics-profiles-api</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.maokai</groupId>
|
||||
<artifactId>maokai-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo</groupId>
|
||||
<artifactId>thor-api</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.apollo</groupId>
|
||||
<artifactId>apollo-api</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.basics</groupId>
|
||||
<artifactId>basics-domainless-api</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.axzo.org</groupId>
|
||||
<artifactId>org-api</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-lang3</artifactId>
|
||||
<version>3.12.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.axzo.karma</groupId>
|
||||
<artifactId>karma-api</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@ -0,0 +1,101 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.dao;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
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;
|
||||
import cn.axzo.nanopart.ess.server.mapper.EssContractMapper;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Repository("essContractDao")
|
||||
public class EssContractDao extends ServiceImpl<EssContractMapper, EssContract> {
|
||||
|
||||
public Optional<EssContract> findByIdempotentCode(String appCode, String idempotentCode) {
|
||||
return lambdaQuery() //
|
||||
.eq(EssContract::getAppCode, appCode) //
|
||||
.eq(EssContract::getIdempotentCode, idempotentCode) //
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
public EssContract getOrThrow(String essContractId) {
|
||||
EssContract contract = findOrNull(essContractId);
|
||||
BizAssertions.assertNotNull(contract, "找不到合同信息, essContractId={}", essContractId);
|
||||
return contract;
|
||||
}
|
||||
|
||||
public EssContract findOrNull(String essContractId) {
|
||||
return find(essContractId, false).orElse(null);
|
||||
}
|
||||
|
||||
public EssContract getForUpdateOrThrow(String essContractId) {
|
||||
EssContract contract = find(essContractId, true).orElse(null);
|
||||
BizAssertions.assertNotNull(contract, "找不到合同信息, 合同id={}", essContractId);
|
||||
return contract;
|
||||
}
|
||||
|
||||
private Optional<EssContract> find(String essContractId, boolean forUpdate) {
|
||||
return lambdaQuery() //
|
||||
.eq(EssContract::getEssContractId, essContractId) //
|
||||
.last(forUpdate, "FOR UPDATE") //
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
public void setEssContractCreated(Long id, String flowId, List<String> essFileIds, List<Approver> approvers) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssContract::getId, id) //
|
||||
.set(EssContract::getEssFieldIds, JSON.toJSONString(essFileIds)) //
|
||||
.set(EssContract::getEssContractId, flowId) //
|
||||
.set(EssContract::getApprovers, JSON.toJSONString(approvers)) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public void updateState(EssContract contract, EssContractState state,
|
||||
List<EssApproveDetail> approveDetailsOrPreserve, String essMessage) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssContract::getId, contract.getId()) //
|
||||
.set(EssContract::getState, state) //
|
||||
.set(StringUtils.isNotBlank(essMessage), EssContract::getEssMessage, essMessage) //
|
||||
.set(CollectionUtils.isNotEmpty(approveDetailsOrPreserve), EssContract::getApproveDetails,
|
||||
approveDetailsOrPreserve == null ? "[]" : JSON.toJSONString(approveDetailsOrPreserve)) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public void setOssFileKey(EssContract contract, String fileKey) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssContract::getId, contract.getId()) //
|
||||
.set(EssContract::getOssFileKey, fileKey) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public void updateAssigment(EssContract contract) {
|
||||
if (contract.getAssignment() == null)
|
||||
return;
|
||||
lambdaUpdate() //
|
||||
.eq(EssContract::getId, contract.getId()) //
|
||||
.set(EssContract::getAssignment, JSON.toJSONString(contract.getAssignment())) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public void updateExt(EssContract contract) {
|
||||
if (contract.getRecordExt() == null)
|
||||
return;
|
||||
lambdaUpdate() //
|
||||
.eq(EssContract::getId, contract.getId()) //
|
||||
.set(EssContract::getRecordExt, JSON.toJSONString(contract.getRecordExt())) //
|
||||
.update();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.dao;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.cloud.context.config.annotation.RefreshScope;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import cn.axzo.nanopart.ess.server.entity.EssLog;
|
||||
import cn.axzo.nanopart.ess.server.mapper.EssLogMapper;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@RefreshScope
|
||||
@Repository("essLogDao")
|
||||
public class EssLogDao extends ServiceImpl<EssLogMapper, EssLog> {
|
||||
|
||||
@Value("${ess.enableRequestLog:true}")
|
||||
private boolean enableRequestLog;
|
||||
|
||||
public void logRequest(String context, Object subject, Object request) {
|
||||
if (enableRequestLog)
|
||||
log(context, subject, "request", request);
|
||||
}
|
||||
|
||||
public void log(String context, Object subject, Object... logContents) {
|
||||
log(null, context, subject, logContents);
|
||||
}
|
||||
|
||||
public void log(Exception exception, String context, Object subject, Object... logContents) {
|
||||
EssLog log = new EssLog();
|
||||
log.setContext(context);
|
||||
log.setSubject(String.valueOf(subject));
|
||||
log.setError(exception);
|
||||
if (logContents != null && logContents.length > 0) {
|
||||
BizAssertions.assertTrue(logContents.length % 2 == 0, "logContents must be even");
|
||||
for (int i = 0; i < logContents.length; i += 2) {
|
||||
BizAssertions.assertTrue(logContents[i] instanceof String, "logContents key must be String");
|
||||
log.addLogContent((String) logContents[i], logContents[i + 1]);
|
||||
}
|
||||
}
|
||||
save(log);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,63 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.dao;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssOrg;
|
||||
import cn.axzo.nanopart.ess.server.mapper.EssOrgMapper;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Repository("essOrgDao")
|
||||
public class EssOrgDao extends ServiceImpl<EssOrgMapper, EssOrg> {
|
||||
|
||||
public List<EssOrg> getByOuIds(Collection<Long> ouIds) {
|
||||
if (CollectionUtils.isEmpty(ouIds))
|
||||
return Collections.emptyList();
|
||||
return lambdaQuery() //
|
||||
.in(EssOrg::getOuId, ouIds) //
|
||||
.list();
|
||||
}
|
||||
|
||||
public EssOrg findOrNull(Long ouId) {
|
||||
return find(ouId, false).orElse(null);
|
||||
}
|
||||
|
||||
public EssOrg findForUpdateOrNull(Long ouId) {
|
||||
return find(ouId, true).orElse(null);
|
||||
}
|
||||
|
||||
private Optional<EssOrg> find(Long ouId, boolean forUpdate) {
|
||||
return lambdaQuery() //
|
||||
.eq(EssOrg::getOuId, ouId) //
|
||||
.last(forUpdate, "FOR UPDATE") //
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
public void setOrgAuthorized(OrgPerson superAdmin) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssOrg::getOuId, superAdmin.getOuId()) //
|
||||
.set(EssOrg::getIsAuthorized, YesOrNo.YES) //
|
||||
.set(EssOrg::getSuperAdminPersonId, superAdmin.getPersonId()) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public void changeSuperAdmin(OrgPerson admin) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssOrg::getOuId, admin.getOuId()) //
|
||||
.set(EssOrg::getSuperAdminPersonId, admin.getPersonId()) //
|
||||
.update();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,61 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.dao;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Repository("essPersonDao")
|
||||
public class EssPersonDao extends ServiceImpl<EssPersonMapper, EssPerson> {
|
||||
|
||||
public EssPerson findOrNull(OrgPerson person) {
|
||||
return findOrNull(person.getOuId(), person.getPersonId());
|
||||
}
|
||||
|
||||
public EssPerson findOrNull(Long ouId, Long personId) {
|
||||
return find(ouId, personId, false).orElse(null);
|
||||
}
|
||||
|
||||
public Optional<EssPerson> find(OrgPerson person, boolean forUpdate) {
|
||||
return find(person.getOuId(), person.getPersonId(), forUpdate);
|
||||
}
|
||||
|
||||
private Optional<EssPerson> find(Long ouId, Long personId, boolean forUpdate) {
|
||||
return lambdaQuery() //
|
||||
.eq(EssPerson::getOuId, ouId) //
|
||||
.eq(EssPerson::getPersonId, personId) //
|
||||
.last(forUpdate, "FOR UPDATE") //
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
public void setOrgPersonState(OrgPerson person, EssPersonState state) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssPerson::getOuId, person.getOuId()) //
|
||||
.eq(EssPerson::getPersonId, person.getPersonId()) //
|
||||
.set(EssPerson::getState, state) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public List<EssPerson> getByPersonIds(Collection<Long> personIds) {
|
||||
if (CollectionUtils.isEmpty(personIds))
|
||||
return Collections.emptyList();
|
||||
return lambdaQuery() //
|
||||
.in(EssPerson::getPersonId, personIds) //
|
||||
.list();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.dao;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealState;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSeal;
|
||||
import cn.axzo.nanopart.ess.server.mapper.EssSealMapper;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Repository("essSealDao")
|
||||
public class EssSealDao extends ServiceImpl<EssSealMapper, EssSeal> {
|
||||
|
||||
public Optional<EssSeal> findByEssSealId(String essSealId) {
|
||||
return lambdaQuery() //
|
||||
.eq(EssSeal::getEssSealId, essSealId) //
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
public void updateState(String essSealId, EssSealState state) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssSeal::getEssSealId, essSealId) //
|
||||
.set(EssSeal::getState, state) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public List<EssSeal> getByOuId(Long ouId) {
|
||||
return lambdaQuery() //
|
||||
.eq(EssSeal::getOuId, ouId) //
|
||||
.list();
|
||||
}
|
||||
|
||||
public void updateSealName(String essSealId, String sealName) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssSeal::getEssSealId, essSealId) //
|
||||
.set(EssSeal::getName, sealName) //
|
||||
.update();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.dao;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
|
||||
import cn.axzo.nanopart.ess.server.mapper.EssSealPersonMapper;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Repository("essSealPersonDao")
|
||||
public class EssSealPersonDao extends ServiceImpl<EssSealPersonMapper, EssSealPerson> {
|
||||
|
||||
public void setPersonAuthorized(String essSealId, Long personId) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssSealPerson::getEssSealId, essSealId) //
|
||||
.eq(EssSealPerson::getPersonId, personId) //
|
||||
.set(EssSealPerson::getIsAuthorized, YesOrNo.YES) //
|
||||
.set(EssSealPerson::getAuthorizeTime, new Date()) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public void setSealPersonAuthorizedBy(String essSealId, Long personId, Long authorizedByPersonId) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssSealPerson::getEssSealId, essSealId) //
|
||||
.eq(EssSealPerson::getPersonId, personId) //
|
||||
.set(EssSealPerson::getAuthorizedByPersonId, authorizedByPersonId) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public void removeSealAuthorization(String essSealId, Long personId) {
|
||||
lambdaUpdate() //
|
||||
.eq(EssSealPerson::getEssSealId, essSealId) //
|
||||
.eq(EssSealPerson::getPersonId, personId) //
|
||||
.set(EssSealPerson::getIsAuthorized, YesOrNo.NO) //
|
||||
.update();
|
||||
}
|
||||
|
||||
public Optional<EssSealPerson> find(String essSealId, Long personId) {
|
||||
return find(essSealId, personId, false);
|
||||
}
|
||||
|
||||
public Optional<EssSealPerson> find(String essSealId, Long personId, boolean forUpdate) {
|
||||
return lambdaQuery() //
|
||||
.eq(EssSealPerson::getEssSealId, essSealId) //
|
||||
.eq(EssSealPerson::getPersonId, personId) //
|
||||
.last(forUpdate, "FOR UPDATE") //
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
public List<EssSealPerson> getByPerson(OrgPerson person) {
|
||||
return lambdaQuery() //
|
||||
.eq(EssSealPerson::getOuId, person.getOuId()) //
|
||||
.eq(EssSealPerson::getPersonId, person.getPersonId()) //
|
||||
.list();
|
||||
}
|
||||
|
||||
public List<EssSealPerson> get(String essSealId) {
|
||||
return lambdaQuery() //
|
||||
.eq(EssSealPerson::getEssSealId, essSealId) //
|
||||
.orderByDesc(EssSealPerson::getId) //
|
||||
.list();
|
||||
}
|
||||
|
||||
public void deleteByPerson(OrgPerson person) {
|
||||
lambdaUpdate()
|
||||
.eq(EssSealPerson::getOuId, person.getOuId())
|
||||
.eq(EssSealPerson::getPersonId, person.getPersonId())
|
||||
.remove();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,203 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.entity;
|
||||
|
||||
import cn.axzo.foundation.dao.support.mysql.type.BaseListTypeHandler;
|
||||
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.Constraint;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractApproveState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractState;
|
||||
import cn.axzo.nanopart.ess.server.entity.domain.Assignment;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@TableName(value = "ess_contract", autoResultMap = true)
|
||||
public class EssContract extends BaseEntity<EssContract> {
|
||||
|
||||
/**
|
||||
* 发起合同的应用或业务场景
|
||||
*/
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 业务编码
|
||||
*/
|
||||
private String bizCode;
|
||||
|
||||
/**
|
||||
* 幂等编码
|
||||
*/
|
||||
private String idempotentCode;
|
||||
|
||||
/**
|
||||
* 合同发起方单位id
|
||||
*/
|
||||
private Long creatorOuId;
|
||||
|
||||
/**
|
||||
* 合同发起方人员id
|
||||
*/
|
||||
private Long creatorPersonId;
|
||||
|
||||
/**
|
||||
* 合同名称
|
||||
*/
|
||||
private String contractName;
|
||||
|
||||
/**
|
||||
* 电子签那边的合同id
|
||||
*/
|
||||
private String essContractId;
|
||||
|
||||
/**
|
||||
* 腾讯电子签的资源id
|
||||
*/
|
||||
@TableField(typeHandler = StringListHandler.class)
|
||||
private List<String> essFieldIds;
|
||||
|
||||
/**
|
||||
* 合同状态. INIT: 合同创建, PART: 合同签署中, ALL: 合同签署完成, REJECT: 合同拒签, CANCEL: 合同撤回, WILLEXPIRE: 合同即将过期, DEADLINE: 合同流签(合同过期), RELIEVED: 解除协议(已解除), INVALID: 合同已失效, EXCEPTION: 合同异常
|
||||
*/
|
||||
private EssContractState state;
|
||||
|
||||
/**
|
||||
* 合并签署方信息
|
||||
*/
|
||||
@TableField(typeHandler = ApproverListHandler.class)
|
||||
private List<Approver> approvers;
|
||||
|
||||
/**
|
||||
* 签署信息(扩展字段)
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private Assignment assignment;
|
||||
|
||||
/**
|
||||
* 签署方的签署情况
|
||||
*/
|
||||
@TableField(typeHandler = ApproveDetailListHandler.class)
|
||||
private List<EssApproveDetail> approveDetails;
|
||||
|
||||
/**
|
||||
* 腾讯电子签那边的消息
|
||||
*/
|
||||
private String essMessage;
|
||||
|
||||
/**
|
||||
* 合同oss信息
|
||||
*/
|
||||
private String ossFileKey;
|
||||
|
||||
/**
|
||||
* 扩展字段
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private RecordExt recordExt;
|
||||
|
||||
public boolean isUploadedToOss() {
|
||||
return StringUtils.isNotBlank(ossFileKey);
|
||||
}
|
||||
|
||||
public RecordExt getOrCreateExt() {
|
||||
if (recordExt == null)
|
||||
recordExt = new RecordExt();
|
||||
return recordExt;
|
||||
}
|
||||
|
||||
public Assignment getOrCreateAssignment() {
|
||||
if (assignment == null)
|
||||
assignment = new Assignment();
|
||||
return assignment;
|
||||
}
|
||||
|
||||
public boolean isOrgSigned(Long ouId) {
|
||||
if (approveDetails == null)
|
||||
return false;
|
||||
for (EssApproveDetail detail : approveDetails) {
|
||||
if (detail.getSignPerson() == null)
|
||||
continue;
|
||||
if (ouId.equals(detail.getSignPerson().getOuId()) && detail.getState() == EssContractApproveState.ACCEPT)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public int approverSize() {
|
||||
return approvers == null ? 0 : approvers.size();
|
||||
}
|
||||
|
||||
public Approver getApprover(Integer idx) {
|
||||
BizAssertions.assertNotNull(approvers, "approver is null");
|
||||
return approvers == null ? null : approvers.get(idx);
|
||||
}
|
||||
|
||||
public Approver getApproverOrThrow(String recipientId) {
|
||||
Approver approver = approvers.stream() //
|
||||
.filter(a -> a.getEssRecipientId().equals(recipientId)) //
|
||||
.findFirst() //
|
||||
.orElse(null);
|
||||
BizAssertions.assertNotNull(approver, "无效的签署编号: {}", recipientId);
|
||||
return approver;
|
||||
}
|
||||
|
||||
public EssApproveDetail getApproveDetailOrThrow(String recipientId) {
|
||||
EssApproveDetail detail = approveDetails.stream() //
|
||||
.filter(d -> d.getRecipientId().equals(recipientId)) //
|
||||
.findFirst() //
|
||||
.orElse(null);
|
||||
BizAssertions.assertNotNull(detail, "无效的签署编号: {}", recipientId);
|
||||
return detail;
|
||||
}
|
||||
|
||||
public boolean isSignPersonsPreset() {
|
||||
if (approvers == null)
|
||||
return false;
|
||||
return approvers.stream().allMatch(Approver::isSignPersonPreset);
|
||||
}
|
||||
|
||||
public boolean shouldDownloadContract() {
|
||||
return isFinalState() || getOrCreateExt().isSaveContractSnapshotArbitrarily();
|
||||
}
|
||||
|
||||
public boolean isFinalState() {
|
||||
return state.finalState();
|
||||
}
|
||||
|
||||
public Constraint getConstraint() {
|
||||
return assignment == null ? null : assignment.getConstraint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class RecordExt {
|
||||
private boolean saveContractSnapshotArbitrarily;
|
||||
}
|
||||
|
||||
// @formatter:off
|
||||
public static class StringListHandler
|
||||
extends BaseListTypeHandler<String> {}
|
||||
public static class ApproveDetailListHandler
|
||||
extends BaseListTypeHandler<EssApproveDetail> {}
|
||||
public static class ApproverListHandler
|
||||
extends BaseListTypeHandler<Approver> {}
|
||||
// @formatter:on
|
||||
}
|
||||
@ -0,0 +1,77 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.entity;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import com.google.common.base.Throwables;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.nanopart.ess.server.http.RequestNoInterceptor;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@TableName(value = "ess_log", autoResultMap = true)
|
||||
public class EssLog extends BaseEntity<EssLog> {
|
||||
|
||||
/**
|
||||
* 上下文
|
||||
*/
|
||||
private String context;
|
||||
|
||||
/**
|
||||
* 主体
|
||||
*/
|
||||
private String subject;
|
||||
|
||||
/**
|
||||
* 腾讯返回的请求id
|
||||
*/
|
||||
private String requestId;
|
||||
|
||||
/**
|
||||
* 是否异常
|
||||
*/
|
||||
private YesOrNo isError;
|
||||
|
||||
/**
|
||||
* 日志内容
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private JSONObject logContent;
|
||||
|
||||
public void addLogContent(String key, Object value) {
|
||||
if (logContent == null)
|
||||
initializeLogContent();
|
||||
logContent.put(key, value);
|
||||
}
|
||||
|
||||
private void initializeLogContent() {
|
||||
logContent = new JSONObject();
|
||||
String requestNo = RequestNoInterceptor.getRequestNo();
|
||||
if (StringUtils.isNotBlank(requestNo))
|
||||
logContent.put("requestNo", requestNo);
|
||||
}
|
||||
|
||||
public void setError(Exception exception) {
|
||||
if (exception == null)
|
||||
return;
|
||||
setIsError(YesOrNo.YES);
|
||||
addLogContent("exception", Throwables.getStackTraceAsString(exception));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,84 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.entity;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@TableName(value = "ess_org", autoResultMap = true)
|
||||
public class EssOrg extends BaseEntity<EssOrg> {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 单位名称
|
||||
*/
|
||||
private String ouName;
|
||||
|
||||
/**
|
||||
* 是否已经认证. YES: 已认证, NO: 未认证
|
||||
*/
|
||||
private YesOrNo isAuthorized;
|
||||
|
||||
/**
|
||||
* 超级管理员人员id
|
||||
*/
|
||||
private Long superAdminPersonId;
|
||||
|
||||
/**
|
||||
* 单位记录创建人id
|
||||
*/
|
||||
private Long createByPersonId;
|
||||
|
||||
/**
|
||||
* 扩展字段
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private RecordExt recordExt;
|
||||
|
||||
public boolean isSuperAdmin(Long personId) {
|
||||
return superAdminPersonId != null && superAdminPersonId.equals(personId);
|
||||
}
|
||||
|
||||
public RecordExt getOrCreateExt() {
|
||||
if (recordExt == null)
|
||||
recordExt = new RecordExt();
|
||||
return recordExt;
|
||||
}
|
||||
|
||||
public boolean isAuthorized() {
|
||||
return isAuthorized.isYes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class RecordExt {
|
||||
|
||||
private Set<Long> historySuperAdmins;
|
||||
|
||||
public boolean isPotentialSuperAdmin(Long personId) {
|
||||
return historySuperAdmins != null && historySuperAdmins.contains(personId);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.entity;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssPersonState;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@TableName(value = "ess_person", autoResultMap = true)
|
||||
public class EssPerson extends BaseEntity<EssPerson> implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 人员id
|
||||
*/
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 人员名称
|
||||
*/
|
||||
private String personName;
|
||||
|
||||
/**
|
||||
* 是否已经认证
|
||||
*/
|
||||
private EssPersonState state;
|
||||
|
||||
/**
|
||||
* 扩展字段
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
public RecordExt recordExt;
|
||||
|
||||
public boolean isAuthorized() {
|
||||
return state == EssPersonState.AUTHORIZED;
|
||||
}
|
||||
|
||||
public boolean is(Long personId) {
|
||||
return this.personId != null && this.personId.equals(personId);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class RecordExt {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,60 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.entity;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealType;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@TableName(value = "ess_seal", autoResultMap = true)
|
||||
public class EssSeal extends BaseEntity<EssSeal> {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 印章在腾讯的id
|
||||
*/
|
||||
private String essSealId;
|
||||
|
||||
/**
|
||||
* 印章名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 印章状态. CREATE: 创建, DELETED: 删除, DISABLED: 停用, ENABLED: 启用
|
||||
*/
|
||||
private EssSealState state;
|
||||
|
||||
/**
|
||||
* 印章类型. OFFICIAL: 公章, CONTRACT: 合同专用章, FINANCE: 财务专用章, PERSONNEL: 人事专用章, INVOICE: 发票专用章, LEGAL_PERSON_SEAL: 法定代表人章, OTHER: 其它
|
||||
*/
|
||||
private EssSealType type;
|
||||
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private RecordExt recordExt;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class RecordExt {
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,75 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.entity;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
@TableName(value = "ess_seal_person", autoResultMap = true)
|
||||
public class EssSealPerson extends BaseEntity<EssSealPerson> implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 印章id
|
||||
*/
|
||||
private String essSealId;
|
||||
|
||||
/**
|
||||
* 人员id
|
||||
*/
|
||||
private Long personId;
|
||||
|
||||
/**
|
||||
* 是否授权. YES: 是, NO: 否
|
||||
*/
|
||||
private YesOrNo isAuthorized;
|
||||
|
||||
/**
|
||||
* 授权人员id
|
||||
*/
|
||||
private Long authorizedByPersonId;
|
||||
|
||||
/**
|
||||
* 授权时间
|
||||
*/
|
||||
private Date authorizeTime;
|
||||
|
||||
/**
|
||||
* 扩展字段
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private RecordExt recordExt;
|
||||
|
||||
public boolean isAuthorized() {
|
||||
return isAuthorized.isYes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
}
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
public static class RecordExt {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.entity.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.Constraint;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class Assignment {
|
||||
|
||||
private Constraint constraint;
|
||||
|
||||
private SignPerOrgs signPerOrgs = new SignPerOrgs();
|
||||
|
||||
}
|
||||
@ -0,0 +1,41 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.entity.domain;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class OuAndPersonId {
|
||||
|
||||
private final Long ouId;
|
||||
private final Long personId;
|
||||
|
||||
public static OuAndPersonId create(Long ouId, Long personId) {
|
||||
return new OuAndPersonId(ouId, personId);
|
||||
}
|
||||
|
||||
public boolean is(Long ouId, Long personId) {
|
||||
return this.ouId.equals(ouId) && this.personId.equals(personId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof OuAndPersonId))
|
||||
return false;
|
||||
OuAndPersonId that = (OuAndPersonId) o;
|
||||
return Objects.equals(ouId, that.ouId) && Objects.equals(personId, that.personId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(ouId, personId);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
package cn.axzo.nanopart.ess.server.entity.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter @Getter
|
||||
public class SignPerOrg implements OrgPerson {
|
||||
private Long ouId;
|
||||
private Long personId;
|
||||
private String recipientId;
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.entity.domain;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class SignPerOrgs {
|
||||
|
||||
private List<SignPerOrg> signPerOrg = new ArrayList<>();
|
||||
|
||||
public Optional<SignPerOrg> find(Long ouId) {
|
||||
return signPerOrg.stream() //
|
||||
.filter(orgPersonInfo -> orgPersonInfo.getOuId().equals(ouId)) //
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public void upsert(OrgPerson person, String recipientId) {
|
||||
remove(person.getOuId());
|
||||
add(person, recipientId);
|
||||
}
|
||||
|
||||
public void remove(Long ouId) {
|
||||
signPerOrg.removeIf(org -> org.getOuId().equals(ouId));
|
||||
}
|
||||
|
||||
public void add(OrgPerson person, String recipientId) {
|
||||
SignPerOrg orgPersonInfo = new SignPerOrg();
|
||||
orgPersonInfo.setOuId(person.getOuId());
|
||||
orgPersonInfo.setPersonId(person.getPersonId());
|
||||
orgPersonInfo.setRecipientId(recipientId);
|
||||
signPerOrg.add(orgPersonInfo);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,114 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess;
|
||||
|
||||
import static cn.axzo.nanopart.ess.server.utils.BizAssertions.fail;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ApproverItem;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowByFilesResponse;
|
||||
|
||||
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;
|
||||
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
|
||||
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.entity.EssContract;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssPerson;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.StringObject;
|
||||
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 lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ContractManager {
|
||||
|
||||
public static final String CONTRACT_ID = "contractId";
|
||||
|
||||
private final OrgManager orgManager;
|
||||
private final EssClient essClient;
|
||||
private final EssContractDao essContractDao;
|
||||
private final EssBroadcaster essBroadcaster;
|
||||
private final ContractSupport contractSupport;
|
||||
private final EssLogDao essLogDao;
|
||||
|
||||
@BizTransactional
|
||||
public CreateContractByFileResponse createContractByFile(CreateContractByFileRequest request) {
|
||||
orgManager.ensureOrgAuthorized(request.getCreator().getOuId(), "合同创建单位还未认证电子签");
|
||||
contractSupport.validateCreateContract(request.getContract());
|
||||
essLogDao.logRequest("createContractByFile", request.getBizCode(), request);
|
||||
EssContract contract;
|
||||
try {
|
||||
contract = contractSupport.saveContractByFile(request);
|
||||
}
|
||||
catch (DuplicateKeyException e) {
|
||||
return contractSupport.createDuplicateContractByFileResponse(request);
|
||||
}
|
||||
try {
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(request.getCreator().getOuId());
|
||||
List<String> essFileIds = essClient.uploadDocument(superAdmin, request.getByFile().getBase64Files());
|
||||
ChannelCreateFlowByFilesResponse essResponse = essClient.createContractByFile(superAdmin, essFileIds,
|
||||
request.getByFile(), StringObject.create().put(CONTRACT_ID, contract.getId()).toString());
|
||||
List<String> essRecipientIds = Arrays.stream(essResponse.getApprovers()) //
|
||||
.map(ApproverItem::getRecipientId) //
|
||||
.collect(toList());
|
||||
for (int i = 0; i < contract.approverSize(); i++)
|
||||
contract.getApprover(i).setEssRecipientId(essRecipientIds.get(i));
|
||||
essContractDao.setEssContractCreated(contract.getId(), essResponse.getFlowId(), essFileIds,
|
||||
contract.getApprovers());
|
||||
essBroadcaster.fireContractStateChanged(contract);
|
||||
CreateContractByFileResponse response = new CreateContractByFileResponse();
|
||||
response.setEssContractId(essResponse.getFlowId());
|
||||
response.setEssRecipientIds(essRecipientIds);
|
||||
return response;
|
||||
}
|
||||
catch (TencentCloudSDKException e) {
|
||||
throw fail(e, "腾讯返回: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void revokeContract(RevokeContractRequest request) {
|
||||
essLogDao.logRequest("revokeContract", request.getEssContractId(), request);
|
||||
// lock when updating state
|
||||
EssContract contract = essContractDao.getForUpdateOrThrow(request.getEssContractId());
|
||||
BizAssertions.assertFalse(contract.isFinalState(), "合同已是终态 {}, 无法撤销", contract.getState().description());
|
||||
EssPerson superAdmin = getContractSuperAdmin(contract);
|
||||
essClient.revokeContract(superAdmin, contract.getEssContractId(), request.getReason());
|
||||
updateContractState(contract, EssContractState.CANCEL, null, request.getReason());
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void updateContractState(EssContract contract, EssContractState state, List<EssApproveDetail> approveDetails,
|
||||
String essMessage) {
|
||||
EssContract reload = essContractDao.getForUpdateOrThrow(contract.getEssContractId());
|
||||
if (reload.isFinalState()) {
|
||||
log.warn("合同[{}]已是最终状态[{}], 无法更新状态至{}", reload.getEssContractId(), reload.getState(), state.description());
|
||||
}
|
||||
else {
|
||||
essContractDao.updateState(contract, state, approveDetails, essMessage);
|
||||
essBroadcaster.fireContractStateChanged(contract);
|
||||
}
|
||||
}
|
||||
|
||||
public EssPerson getContractSuperAdmin(EssContract contract) {
|
||||
return orgManager.getSuperAdminOrThrow(contract.getCreatorOuId());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,570 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess;
|
||||
|
||||
import static cn.axzo.nanopart.ess.server.ess.EssClient.Func.func;
|
||||
import static cn.axzo.nanopart.ess.server.utils.BizAssertions.fail;
|
||||
import static cn.axzo.nanopart.ess.server.utils.IdBuilder.idbuilder;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.tencentcloudapi.common.Credential;
|
||||
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
||||
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.ApproverOption;
|
||||
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.ChannelCreateFlowApproversRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowByFilesRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowByFilesResponse;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowSignUrlRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowSignUrlResponse;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateOrganizationBatchSignUrlRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateOrganizationBatchSignUrlResponse;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateSealPolicyRequest;
|
||||
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.ChannelDescribeOrganizationSealsRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelDescribeOrganizationSealsResponse;
|
||||
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.CreateFlowForwardsRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsResponse;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.DescribeResourceUrlsByFlowsRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.DescribeResourceUrlsByFlowsResponse;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.FillApproverInfo;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.FlowApproverInfo;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.FlowForwardInfo;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.OccupiedSeal;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ProxyOrganizationOperator;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.SyncProxyOrganizationOperatorsRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.UploadFile;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.UploadFilesRequest;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.UploadFilesResponse;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.UserInfo;
|
||||
|
||||
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||
import cn.axzo.nanopart.ess.api.domain.CreateContractInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssConsoleUrlEndpoint;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssEmbedType;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealType;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssLogDao;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssLog;
|
||||
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.EssClient.Func.FuncBuilder;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.OrgOpenId;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.PersonOpenId;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.EssProps;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.EssSupport;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.OrgProfiles;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.PersonProfiles;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
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 newTransaction;
|
||||
private EssbasicClient manage;
|
||||
private EssbasicClient file;
|
||||
|
||||
public String createConsoleLoginUrl(EssOrg org, EssPerson person, EssConsoleUrlEndpoint endpoint,
|
||||
boolean essCheckLoginPerson) {
|
||||
PersonProfileDto personProfile = essSupport.getPersonProfileOrThrow(person);
|
||||
CreateConsoleLoginUrlRequest request = new CreateConsoleLoginUrlRequest();
|
||||
request.setEndpoint(endpoint.getCode());
|
||||
request.setEndpoint(request.getEndpoint());
|
||||
request.setAgent(agent(person));
|
||||
String orgName = org.getOuName() + (props.isTestEnv() ? "测试" : "");
|
||||
if (props.isTestEnv())
|
||||
orgName = orgName.replaceAll("中国", "zhongguo");
|
||||
request.setProxyOrganizationName(orgName);
|
||||
if (essCheckLoginPerson) {
|
||||
request.setProxyOperatorName(personProfile.getRealName());
|
||||
request.setProxyOperatorMobile(personProfile.getPhone());
|
||||
}
|
||||
CreateConsoleLoginUrlResponse response = exec(func() //
|
||||
.context("CreateConsoleLoginUrl") //
|
||||
.subject(idbuilder() //
|
||||
.append(person.getOuId()) //
|
||||
.append(person.getPersonId()) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.CreateConsoleLoginUrl(request)));
|
||||
return response.getConsoleUrl();
|
||||
}
|
||||
|
||||
public String getEmbedWebUrl(EssPerson contextPerson, EssEmbedType embedType, String businessId) {
|
||||
if (embedType.businessIdRequired())
|
||||
BizAssertions.assertNotBlank(businessId, "内嵌类型为{}时业务ID不能为空", embedType.name());
|
||||
ChannelCreateEmbedWebUrlRequest request = new ChannelCreateEmbedWebUrlRequest();
|
||||
request.setAgent(agent(contextPerson));
|
||||
request.setBusinessId(businessId);
|
||||
request.setEmbedType(embedType.essCode());
|
||||
request.setHiddenComponents(true);
|
||||
ChannelCreateEmbedWebUrlResponse response = exec(func() //
|
||||
.context("ChannelCreateEmbedWebUrl") //
|
||||
.subject(idbuilder() //
|
||||
.append(embedType.name()) //
|
||||
.append(StringUtils.isBlank(businessId) ? contextPerson.getOuId() : businessId) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelCreateEmbedWebUrl(request)));
|
||||
return response.getWebUrl();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public OccupiedSeal getSealInfo(EssPerson superAdmin, String sealId) {
|
||||
ChannelDescribeOrganizationSealsRequest request = new ChannelDescribeOrganizationSealsRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setSealId(sealId);
|
||||
request.setSealStatuses(new String[] { "ALL" });
|
||||
request.setLimit(99L);
|
||||
ChannelDescribeOrganizationSealsResponse response = exec(func() //
|
||||
.context("ChannelDescribeOrganizationSeals") //
|
||||
.subject(sealId) //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelDescribeOrganizationSeals(request)));
|
||||
OccupiedSeal[] seals = response.getSeals();
|
||||
if (seals == null || seals.length == 0)
|
||||
return null;
|
||||
return seals[0];
|
||||
}
|
||||
|
||||
public void addSealAuthorization(EssPerson superAdmin, EssSeal seal, EssSealPerson sealPerson) {
|
||||
ChannelCreateSealPolicyRequest request = new ChannelCreateSealPolicyRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setSealId(seal.getEssSealId());
|
||||
request.setUserIds(new String[] { PersonOpenId.create(sealPerson).toOpenId() });
|
||||
exec(func() //
|
||||
.context("ChannelCreateSealPolicy") //
|
||||
.subject(idbuilder() //
|
||||
.append(seal.getEssSealId()) //
|
||||
.append(sealPerson.getPersonId()) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelCreateSealPolicy(request)));
|
||||
}
|
||||
|
||||
public void removeSealAuthorization(EssPerson superAdmin, EssSeal seal, EssSealPerson sealPerson) {
|
||||
ChannelDeleteSealPoliciesRequest request = new ChannelDeleteSealPoliciesRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setSealId(seal.getEssSealId());
|
||||
request.setUserIds(new String[] { PersonOpenId.create(sealPerson).toOpenId() });
|
||||
exec(func() //
|
||||
.context("ChannelDeleteSealPolicies") //
|
||||
.subject(idbuilder() //
|
||||
.append(seal.getEssSealId()) //
|
||||
.append(sealPerson.getPersonId()) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelDeleteSealPolicies(request)));
|
||||
}
|
||||
|
||||
List<String> uploadDocument(EssPerson superAdmin, List<String> base64Files) throws TencentCloudSDKException {
|
||||
return uploadFile(superAdmin, UploadFileBusinessType.DOCUMENT, base64Files);
|
||||
}
|
||||
|
||||
List<String> uploadTemplate(EssPerson superAdmin, List<String> base64Files) throws TencentCloudSDKException {
|
||||
return uploadFile(superAdmin, UploadFileBusinessType.TEMPLATE, base64Files);
|
||||
}
|
||||
|
||||
private List<String> uploadFile(EssPerson superAdmin, UploadFileBusinessType businessType, List<String> base64Files)
|
||||
throws TencentCloudSDKException {
|
||||
BizAssertions.assertFalse(base64Files.isEmpty(), "文件不能为空");
|
||||
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(files.toArray(new UploadFile[0]));
|
||||
request.setBusinessType(businessType.name());
|
||||
UploadFilesResponse response = call(Func.<UploadFilesResponse> func() //
|
||||
.context("UploadFiles") //
|
||||
.subject("") //
|
||||
.subject2(r -> r.getFileIds()[0]) //
|
||||
.request(request) //
|
||||
.command(() -> file.UploadFiles(request)));
|
||||
return Arrays.asList(response.getFileIds());
|
||||
}
|
||||
|
||||
ChannelCreateFlowByFilesResponse createContractByFile(EssPerson superAdmin, List<String> contractFileIds,
|
||||
CreateContractInfo contract, String customerData) throws TencentCloudSDKException {
|
||||
OrgProfiles orgProfiles = OrgProfiles.wrap(essSupport.getOrgProfiles( //
|
||||
contract.getApprovers().stream() //
|
||||
.filter(Approver::isSignPersonPreset) //
|
||||
.map(Approver::getOuId) //
|
||||
.collect(toList())));
|
||||
PersonProfiles personProfiles = PersonProfiles.wrap(essSupport.getPersonProfiles( //
|
||||
contract.getApprovers().stream() //
|
||||
.filter(Approver::isSignPersonPreset) //
|
||||
.map(Approver::getPersonId) //
|
||||
.collect(toList())));
|
||||
ArrayList<FlowApproverInfo> approvers = new ArrayList<>();
|
||||
for (Approver approver : contract.getApprovers()) {
|
||||
FlowApproverInfo approverInfo = new FlowApproverInfo();
|
||||
approvers.add(approverInfo);
|
||||
ApproverOption approverOption = new ApproverOption();
|
||||
if (approver.getSignPerson() == null) {
|
||||
approverOption.setFillType(1L);
|
||||
}
|
||||
else {
|
||||
OrganizationalUnitVO orgProfile = orgProfiles.getOrThrow(approver.getOuId());
|
||||
PersonProfileDto personProfile = personProfiles.getOrThrow(approver.getPersonId());
|
||||
approverInfo.setName(personProfile.getRealName());
|
||||
approverInfo.setMobile(personProfile.getPhone());
|
||||
approverInfo.setOpenId(PersonOpenId.create(approver).toOpenId());
|
||||
approverInfo.setOrganizationName(orgProfile.getName());
|
||||
approverInfo.setOrganizationOpenId(OrgOpenId.ofPerson(approver).toOpenId());
|
||||
}
|
||||
if (approver.getSignOption() != null) {
|
||||
approverOption.setNoRefuse(approver.getSignOption().isNoRefuse());
|
||||
approverOption.setNoTransfer(approver.getSignOption().isNoTransfer());
|
||||
}
|
||||
approverInfo.setApproverOption(approverOption);
|
||||
approverInfo.setApproverType(approver.getApproverType().name());
|
||||
approverInfo.setNotifyType("NONE");
|
||||
approverInfo.setPreReadTime(approver.getPreReadTimeSeconds());
|
||||
if (CollectionUtils.isNotEmpty(approver.getSealTypes())) {
|
||||
ComponentLimit componentLimit = new ComponentLimit();
|
||||
componentLimit.setComponentType("SIGN_SEAL");
|
||||
componentLimit.setComponentValue( //
|
||||
approver.getSealTypes().stream() //
|
||||
.map(EssSealType::getUseForLimitCode) //
|
||||
.distinct() //
|
||||
.toArray(String[]::new));
|
||||
approverInfo.setAddSignComponentsLimits(new ComponentLimit[] { componentLimit });
|
||||
}
|
||||
}
|
||||
ChannelCreateFlowByFilesRequest request = new ChannelCreateFlowByFilesRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setSignBeanTag(contract.getSignBeanTag());
|
||||
request.setFlowName(contract.getContractName());
|
||||
request.setFileIds(contractFileIds.toArray(new String[0]));
|
||||
request.setFlowApprovers(approvers.toArray(new FlowApproverInfo[0]));
|
||||
request.setUnordered(!contract.isSignOrdered());
|
||||
request.setCustomerData(customerData);
|
||||
if (contract.getDeadlineMs() != null)
|
||||
request.setDeadline(contract.getDeadlineMs() / 1000);
|
||||
return call(Func.<ChannelCreateFlowByFilesResponse> func() //
|
||||
.context("ChannelCreateFlowByFiles") //
|
||||
.subject(contract.getContractName()) //
|
||||
.subject2(ChannelCreateFlowByFilesResponse::getFlowId) //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelCreateFlowByFiles(request)));
|
||||
}
|
||||
|
||||
void revokeContract(EssPerson superAdmin, String essContractId, String reason) {
|
||||
ChannelCancelFlowRequest request = new ChannelCancelFlowRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setFlowId(essContractId);
|
||||
request.setCancelMessage(reason);
|
||||
exec(func() //
|
||||
.context("ChannelCancelFlow") //
|
||||
.subject(essContractId) //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelCancelFlow(request)));
|
||||
}
|
||||
|
||||
public String getContractPDFUrl(EssPerson superAdmin, String essContractId) {
|
||||
DescribeResourceUrlsByFlowsRequest request = new DescribeResourceUrlsByFlowsRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setFlowIds(new String[] { essContractId });
|
||||
DescribeResourceUrlsByFlowsResponse response = exec(func() //
|
||||
.context("DescribeResourceUrlsByFlows") //
|
||||
.subject(essContractId) //
|
||||
.request(request) //
|
||||
.command(() -> manage.DescribeResourceUrlsByFlows(request)));
|
||||
return response.getFlowResourceUrlInfos()[0].getResourceUrlInfos()[0].getUrl();
|
||||
}
|
||||
|
||||
void createFlowApprovers(EssPerson superAdmin, String essContractId, String recipientId, EssPerson signPerson) {
|
||||
OrganizationalUnitVO org = essSupport.getOrgProfileOrThrow(signPerson.getOuId());
|
||||
FillApproverInfo approver = new FillApproverInfo();
|
||||
approver.setRecipientId(recipientId);
|
||||
approver.setOpenId(PersonOpenId.create(signPerson).toOpenId());
|
||||
approver.setOrganizationOpenId(OrgOpenId.ofPerson(signPerson).toOpenId());
|
||||
approver.setOrganizationName(org.getName());
|
||||
ChannelCreateFlowApproversRequest request = new ChannelCreateFlowApproversRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setApprovers(new FillApproverInfo[] { approver });
|
||||
request.setFlowId(essContractId);
|
||||
request.setFillApproverType(1L);
|
||||
exec(func() //
|
||||
.context("ChannelCreateFlowApprovers") //
|
||||
.subject(idbuilder() //
|
||||
.append(essContractId) //
|
||||
.append(signPerson.getPersonId()) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelCreateFlowApprovers(request)));
|
||||
}
|
||||
|
||||
public String createPcSignUrl(EssPerson superAdmin, String essContractId, EssPerson signPerson) {
|
||||
ChannelCreateOrganizationBatchSignUrlRequest request = new ChannelCreateOrganizationBatchSignUrlRequest();
|
||||
request.setAgent(agent(signPerson));
|
||||
request.setFlowIds(new String[] { essContractId });
|
||||
request.setOpenId(PersonOpenId.create(signPerson).toOpenId());
|
||||
ChannelCreateOrganizationBatchSignUrlResponse response = exec(func() //
|
||||
.context("ChannelCreateOrganizationBatchSignUrl").subject(idbuilder() //
|
||||
.append(essContractId) //
|
||||
.append(signPerson.getPersonId()) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelCreateOrganizationBatchSignUrl(request)));
|
||||
return response.getSignUrl();
|
||||
}
|
||||
|
||||
public String createSignUrls(EssPerson superAdmin, String essContractId, String recipientId, OrgPerson signPerson) {
|
||||
CreateSignUrlsRequest request = new CreateSignUrlsRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setFlowIds(new String[] { essContractId });
|
||||
request.setOpenId(PersonOpenId.create(signPerson).toOpenId());
|
||||
request.setOrganizationOpenId(OrgOpenId.ofPerson(signPerson).toOpenId());
|
||||
request.setAutoJumpBack(true);
|
||||
if (StringUtils.isNotBlank(recipientId)) {
|
||||
request.setRecipientIds(new String[] { recipientId });
|
||||
request.setGenerateType("RECIPIENT");
|
||||
}
|
||||
CreateSignUrlsResponse response = exec(func() //
|
||||
.context("CreateSignUrls") //
|
||||
.subject(idbuilder() //
|
||||
.append(essContractId) //
|
||||
.append(signPerson.getPersonId()) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.CreateSignUrls(request)));
|
||||
return response.getSignUrlInfos()[0].getSignUrl();
|
||||
}
|
||||
|
||||
public String channelCreateFlowSignUrl(EssPerson superAdmin, String essContractId, EssPerson signPerson) {
|
||||
FlowApproverInfo approver = new FlowApproverInfo();
|
||||
approver.setOpenId(PersonOpenId.create(signPerson).toOpenId());
|
||||
approver.setOrganizationOpenId(OrgOpenId.ofPerson(signPerson).toOpenId());
|
||||
ChannelCreateFlowSignUrlRequest request = new ChannelCreateFlowSignUrlRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setFlowId(essContractId);
|
||||
request.setFlowApproverInfos(new FlowApproverInfo[] { approver });
|
||||
ChannelCreateFlowSignUrlResponse response = exec(func() //
|
||||
.context("ChannelCreateFlowSignUrl") //
|
||||
.subject(idbuilder() //
|
||||
.append(essContractId) //
|
||||
.append(signPerson.getPersonId()) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelCreateFlowSignUrl(request)));
|
||||
return response.getFlowApproverUrlInfos()[0].getSignUrl();
|
||||
}
|
||||
|
||||
public void forward(EssPerson superAdmin, String essContractId, String recipientId, EssPerson signPerson) {
|
||||
CreateFlowForwardsRequest request = new CreateFlowForwardsRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setTargetOpenId(PersonOpenId.create(signPerson).toOpenId());
|
||||
FlowForwardInfo forward = new FlowForwardInfo();
|
||||
forward.setFlowId(essContractId);
|
||||
forward.setRecipientId(recipientId);
|
||||
request.setFlowForwardInfos(new FlowForwardInfo[] { forward });
|
||||
exec(func() //
|
||||
.context("CreateFlowForwards") //
|
||||
.subject(idbuilder() //
|
||||
.append(essContractId) //
|
||||
.append(signPerson.getPersonId()) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.CreateFlowForwards(request)));
|
||||
}
|
||||
|
||||
public void setEmployeeResigned(EssPerson superAdmin, EssPerson person) {
|
||||
ProxyOrganizationOperator operator = new ProxyOrganizationOperator();
|
||||
operator.setId(PersonOpenId.create(person).toOpenId());
|
||||
operator.setName(person.getPersonName());
|
||||
SyncProxyOrganizationOperatorsRequest request = new SyncProxyOrganizationOperatorsRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setOperatorType("RESIGN");
|
||||
request.setProxyOrganizationOperators(new ProxyOrganizationOperator[] { operator });
|
||||
exec(func() //
|
||||
.context("SyncProxyOrganizationOperators") //
|
||||
.subject(idbuilder() //
|
||||
.append(person.getOuId()) //
|
||||
.append(person.getPersonId()) //
|
||||
.append(request.getOperatorType()) //
|
||||
.build()) //
|
||||
.request(request) //
|
||||
.command(() -> manage.SyncProxyOrganizationOperators(request)));
|
||||
}
|
||||
|
||||
public ChannelDescribeEmployeesResponse getOrgPerson(EssPerson superAdmin, EssOrg org, Long offset) {
|
||||
ChannelDescribeEmployeesRequest request = new ChannelDescribeEmployeesRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setOffset(offset);
|
||||
request.setLimit(20L);
|
||||
return exec(func() //
|
||||
.context("ChannelDescribeEmployees") //
|
||||
.subject(org.getOuId() + "") //
|
||||
.request(request) //
|
||||
.command(() -> manage.ChannelDescribeEmployees(request)));
|
||||
}
|
||||
|
||||
private Agent agent(EssPerson person) {
|
||||
Agent agent = new Agent();
|
||||
UserInfo userInfo = new UserInfo();
|
||||
agent.setAppId(props.getAppId());
|
||||
agent.setProxyAppId("");
|
||||
agent.setProxyOrganizationOpenId(OrgOpenId.ofPerson(person).toOpenId());
|
||||
userInfo.setOpenId(PersonOpenId.create(person).toOpenId());
|
||||
agent.setProxyOperator(userInfo);
|
||||
return agent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
manage = createEssbasicClient(props.getApiEndPoint());
|
||||
file = createEssbasicClient(props.getFileEndPoint());
|
||||
}
|
||||
|
||||
private EssbasicClient createEssbasicClient(String apiEndPoint) {
|
||||
Credential cred = new Credential(props.getSecretId(), props.getSecretKey());
|
||||
HttpProfile httpProfile = new HttpProfile();
|
||||
httpProfile.setEndpoint(apiEndPoint);
|
||||
ClientProfile clientProfile = new ClientProfile();
|
||||
clientProfile.setHttpProfile(httpProfile);
|
||||
return new EssbasicClient(cred, "", clientProfile);
|
||||
}
|
||||
|
||||
private <T> T exec(FuncBuilder<?> builder) {
|
||||
try {
|
||||
return call(builder);
|
||||
}
|
||||
catch (TencentCloudSDKException e) {
|
||||
throw fail(e, "腾讯返回: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private <T> T call(FuncBuilder<?> builder) throws TencentCloudSDKException {
|
||||
//noinspection unchecked
|
||||
Func<Object> func = (Func<Object>) builder.build();
|
||||
EssLog essLog = new EssLog();
|
||||
essLog.setCreateAt(new Date());
|
||||
essLog.setUpdateAt(new Date());
|
||||
essLog.setContext(String.format("ess:api:%s", func.context));
|
||||
essLog.addLogContent("essRequest", func.request);
|
||||
essLog.setSubject(func.subject == null ? "" : func.subject);
|
||||
|
||||
T response = null;
|
||||
TencentCloudSDKException exception = null;
|
||||
try {
|
||||
//noinspection unchecked
|
||||
response = (T) func.command.exec();
|
||||
essLog.addLogContent("essResponse", response);
|
||||
if (func.subject2 != null) {
|
||||
String newSubject = func.subject2.apply(response);
|
||||
if (newSubject != null)
|
||||
essLog.setSubject(newSubject);
|
||||
}
|
||||
if (response != null) {
|
||||
Method method = ReflectionUtils.findMethod(response.getClass(), "getRequestId");
|
||||
if (method != null) {
|
||||
method.setAccessible(true);
|
||||
String requestId = (String) ReflectionUtils.invokeMethod(method, response);
|
||||
essLog.setRequestId(requestId);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (TencentCloudSDKException e) {
|
||||
log.warn("腾讯云接口调用失败", e);
|
||||
exception = e;
|
||||
essLog.setError(e);
|
||||
Matcher matcher = ESS_ERROR_REQUEST_ID_PATTERN.matcher(Throwables.getStackTraceAsString(e));
|
||||
if (matcher.find()) {
|
||||
String requestId = matcher.group(1);
|
||||
essLog.setRequestId(requestId);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
newTransaction.executeWithoutResult(unused -> essLogDao.save(essLog));
|
||||
}
|
||||
if (exception != null)
|
||||
throw exception;
|
||||
return response;
|
||||
}
|
||||
|
||||
public enum UploadFileBusinessType {
|
||||
DOCUMENT, TEMPLATE
|
||||
}
|
||||
|
||||
@lombok.Builder
|
||||
public static class Func<T> {
|
||||
final String context;
|
||||
final String subject;
|
||||
final Function<T, String> subject2;
|
||||
final Object request;
|
||||
final TencentCloudFunc<T> command;
|
||||
|
||||
public static <T> FuncBuilder<T> func() {
|
||||
return Func.builder();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private interface TencentCloudFunc<T> {
|
||||
T exec() throws TencentCloudSDKException;
|
||||
}
|
||||
|
||||
@Bean(NEW_TRANSACTION)
|
||||
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
|
||||
TransactionTemplate transactionTemplate = new TransactionTemplate(transactionManager);
|
||||
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
return transactionTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,235 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess;
|
||||
|
||||
import static cn.axzo.nanopart.ess.server.utils.IdBuilder.idbuilder;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
|
||||
import cn.axzo.nanopart.ess.api.enums.Constraint;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssEmbedType.EssSubject;
|
||||
import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AssignSignUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetEmbedWebUrlRequest;
|
||||
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;
|
||||
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.entity.EssContract;
|
||||
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.OrgAndPerson;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.SealAndPerson;
|
||||
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 lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class EssService {
|
||||
|
||||
private final OrgManager orgManager;
|
||||
private final ContractManager contractManager;
|
||||
private final EssClient essClient;
|
||||
private final EssSealDao essSealDao;
|
||||
private final EssSealPersonDao essSealPersonDao;
|
||||
private final EssContractDao essContractDao;
|
||||
private final EssPersonDao essPersonDao;
|
||||
private final OssService ossService;
|
||||
private final EssLogDao essLogDao;
|
||||
private final EssBroadcaster essBroadcaster;
|
||||
|
||||
@BizTransactional
|
||||
public String createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) {
|
||||
String subject = idbuilder() //
|
||||
.append(request.getOuId()) //
|
||||
.append(request.getPersonId()) //
|
||||
.build();
|
||||
essLogDao.logRequest("createConsoleLoginUrl", subject, request);
|
||||
OrgAndPerson orgAndPerson = orgManager.createConsoleLoginUrl(request);
|
||||
return essClient.createConsoleLoginUrl(orgAndPerson.getOrg(), orgAndPerson.getPerson(), request.getEndpoint(),
|
||||
request.isEssCheckLoginPerson());
|
||||
}
|
||||
|
||||
public String getEmbedWebUrl(GetEmbedWebUrlRequest request) {
|
||||
EssPerson contextPerson;
|
||||
if (request.getEmbedType().essSubject() == EssSubject.CONTRACT) {
|
||||
BizAssertions.assertNotBlank(request.getBusinessId(), "合同ID不能为空");
|
||||
EssContract contract = essContractDao.getOrThrow(request.getBusinessId());
|
||||
contextPerson = contractManager.getContractSuperAdmin(contract);
|
||||
}
|
||||
else {
|
||||
contextPerson = orgManager.getSuperAdminOrThrow(request.getOuId());
|
||||
}
|
||||
return essClient.getEmbedWebUrl(contextPerson, request.getEmbedType(), request.getBusinessId());
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void essAddSealAuthorization(AddSealAuthorizationRequest request) {
|
||||
String subject = idbuilder() //
|
||||
.append(request.getEssSealId()) //
|
||||
.append(request.getPersonId()) //
|
||||
.build();
|
||||
essLogDao.logRequest("essAddSealAuthorization", subject, request);
|
||||
SealAndPerson sealAndPerson = getSealAndPersonOrThrow(request);
|
||||
EssSealPerson sealPerson = sealAndPerson.getSealPerson();
|
||||
if (sealPerson.isAuthorized())
|
||||
return;
|
||||
EssPerson essPerson = essPersonDao.findOrNull(sealPerson);
|
||||
BizAssertions.assertNotNull(essPerson, "人员不存在: {}", sealPerson.getPersonId());
|
||||
BizAssertions.assertTrue(essPerson.isAuthorized(), "人员未加入单位, 无法授权");
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(sealAndPerson.getSeal().getOuId());
|
||||
essClient.addSealAuthorization(superAdmin, sealAndPerson.getSeal(), sealPerson);
|
||||
orgManager.maybeAddPersonAndSetSealAuthorized(request.getEssSealId(), request.getPersonId());
|
||||
Long operatorPersonId = request.getOperatorPersonId();
|
||||
if (operatorPersonId != null && operatorPersonId > 0)
|
||||
orgManager.setSealPersonAuthorizedBy(request.getEssSealId(), request.getPersonId(), operatorPersonId);
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void essRemoveSealAuthorization(RemoveSealAuthorizationRequest request) {
|
||||
String subject = idbuilder() //
|
||||
.append(request.getEssSealId()) //
|
||||
.append(request.getPersonId()) //
|
||||
.build();
|
||||
essLogDao.logRequest("essRemoveSealAuthorization", subject, request);
|
||||
SealAndPerson sealAndPerson = getSealAndPersonOrThrow(request);
|
||||
if (!sealAndPerson.getSealPerson().isAuthorized())
|
||||
return;
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(sealAndPerson.getSeal().getOuId());
|
||||
BizAssertions.assertFalse(superAdmin.is(request.getPersonId()), "不能取消超级管理员的印章授权");
|
||||
essClient.removeSealAuthorization(superAdmin, sealAndPerson.getSeal(), sealAndPerson.getSealPerson());
|
||||
orgManager.removeSealAuthorization(request.getEssSealId(), request.getPersonId());
|
||||
}
|
||||
|
||||
private SealAndPerson getSealAndPersonOrThrow(SealAndPersonRequest request) {
|
||||
EssSeal seal = essSealDao.findByEssSealId(request.getEssSealId()).orElse(null);
|
||||
BizAssertions.assertNotNull(seal, "印章不存在: {}", request.getEssSealId());
|
||||
EssSealPerson sealPerson = essSealPersonDao.find(request.getEssSealId(), request.getPersonId()).orElse(null);
|
||||
BizAssertions.assertNotNull(sealPerson, "印章人员不存在: {}", request.getEssSealId(), request.getPersonId());
|
||||
return new SealAndPerson(seal, sealPerson);
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public String assignSignUrl(AssignSignUrlRequest request) {
|
||||
String subject = idbuilder() //
|
||||
.append(request.getEssContractId()) //
|
||||
.append(request.getOuId()) //
|
||||
.append(request.getPersonId()) //
|
||||
.build();
|
||||
essLogDao.logRequest("assignSignUrl", subject, request);
|
||||
EssPerson signPerson = essPersonDao.findOrNull(request);
|
||||
BizAssertions.assertNotNull(signPerson, "当前签署人员未加入单位, 无法签署");
|
||||
EssContract contract = essContractDao.getForUpdateOrThrow(request.getEssContractId());
|
||||
BizAssertions.assertFalse(contract.isFinalState(), "合同已是最终状态 {}, 无法签署", contract.getState());
|
||||
Approver approver = contract.getApproverOrThrow(request.getRecipientId());
|
||||
BizAssertions.assertFalse(approver.isSignPersonPreset(), "非动态签署人不能使用该接口签署");
|
||||
if (contract.getConstraint() == Constraint.ONE_PERSON_PER_ORG) {
|
||||
BizAssertions.assertFalse(contract.isOrgSigned(request.getOuId()), "该单位已签署, 无法再次签署");
|
||||
contract.getOrCreateAssignment().getSignPerOrgs().find(request.getOuId()).ifPresent(org -> {
|
||||
BizAssertions.assertEquals(org.getRecipientId(), request.getRecipientId(), "单位的签署编号不能变化");
|
||||
if (!org.getPersonId().equals(request.getPersonId())) {
|
||||
EssPerson signSuperAdmin = orgManager.getSuperAdminOrThrow(signPerson.getOuId());
|
||||
try {
|
||||
essClient.forward(signSuperAdmin, contract.getEssContractId(), request.getRecipientId(),
|
||||
signPerson);
|
||||
} catch (Exception e) {
|
||||
essLogDao.log(e, "assignSignUrl", subject);
|
||||
log.warn("转发签署人失败", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
contract.getOrCreateAssignment().getSignPerOrgs().upsert(signPerson, request.getRecipientId());
|
||||
essContractDao.updateAssigment(contract);
|
||||
}
|
||||
EssPerson superAdmin = contractManager.getContractSuperAdmin(contract);
|
||||
if (request.getEndpoint() == SignUrlEndpoint.PC) {
|
||||
essClient.createFlowApprovers(superAdmin, contract.getEssContractId(), request.getRecipientId(),
|
||||
signPerson);
|
||||
return essClient.createPcSignUrl(superAdmin, contract.getEssContractId(), signPerson);
|
||||
}
|
||||
else if (request.getEndpoint() == SignUrlEndpoint.WEIXIN_APP)
|
||||
return essClient.createSignUrls(superAdmin, contract.getEssContractId(), request.getRecipientId(),
|
||||
signPerson);
|
||||
else
|
||||
throw BizAssertions.fail("不支持的签署端点: {}", request.getEndpoint());
|
||||
}
|
||||
|
||||
public String getContractPDFUrl(String essContractId) {
|
||||
EssContract contract = essContractDao.getOrThrow(essContractId);
|
||||
if (contract.isUploadedToOss())
|
||||
return ossService.getOssUrl(contract.getOssFileKey());
|
||||
// 尝试做补偿
|
||||
maybeScheduleDownloadContractPDF(contract, false);
|
||||
return getContractPDFUrlFromEss(contract);
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void saveContractSnapshot(SaveContractSnapshotRequest request) {
|
||||
essLogDao.logRequest("saveContractSnapshot", request.getEssContractId(), request);
|
||||
EssContract contract = essContractDao.getOrThrow(request.getEssContractId());
|
||||
contract.getOrCreateExt().setSaveContractSnapshotArbitrarily(true);
|
||||
essContractDao.updateExt(contract);
|
||||
maybeScheduleDownloadContractPDF(contract, request.isRetryDownload());
|
||||
}
|
||||
|
||||
public void maybeScheduleDownloadContractPDF(EssContract contract, boolean retryDownload) {
|
||||
EssContract reload = essContractDao.findOrNull(contract.getEssContractId());
|
||||
if (scheduleDownloadPDF(reload, retryDownload))
|
||||
essBroadcaster.fireDownloadContractPDF(contract, retryDownload);
|
||||
}
|
||||
|
||||
private boolean scheduleDownloadPDF(EssContract contract, boolean retryDownload) {
|
||||
if (contract == null)
|
||||
return false;
|
||||
if (contract.isUploadedToOss() && !retryDownload)
|
||||
return false;
|
||||
return contract.shouldDownloadContract();
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void downloadContractPDF(EssContract contract, boolean retryDownload) {
|
||||
if (!scheduleDownloadPDF(contract, retryDownload)) {
|
||||
log.info("合同不需要下载PDF, contract={}", contract);
|
||||
return;
|
||||
}
|
||||
// 终状的合同肯定无需重复下载
|
||||
if (contract.isFinalState() && contract.isUploadedToOss()) {
|
||||
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, "retryDownload",
|
||||
retryDownload);
|
||||
log.info("上传合同到OSS成功, essContractId={}", contract.getEssContractId());
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.warn("上传合同到OSS失败", e);
|
||||
essLogDao.log(e, "uploadContractToOss", contract.getEssContractId(), "retryDownload", retryDownload);
|
||||
}
|
||||
}
|
||||
|
||||
private String getContractPDFUrlFromEss(EssContract contract) {
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(contract.getCreatorOuId());
|
||||
return essClient.getContractPDFUrl(superAdmin, contract.getEssContractId());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,230 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess;
|
||||
|
||||
import static cn.axzo.nanopart.ess.server.utils.IdBuilder.idbuilder;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.OrgPersonInfo;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssPersonState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealType;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.RemoveSealPersonRequest;
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
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.dao.EssSealDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssSealPersonDao;
|
||||
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.OrgAndPerson;
|
||||
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 lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class OrgManager {
|
||||
|
||||
private final EssSupport essSupport;
|
||||
private final EssOrgDao essOrgDao;
|
||||
private final EssPersonDao essPersonDao;
|
||||
private final EssSealDao essSealDao;
|
||||
private final EssSealPersonDao essSealPersonDao;
|
||||
private final EssLogDao essLogDao;
|
||||
|
||||
// !! login
|
||||
|
||||
@BizTransactional
|
||||
public OrgAndPerson createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) {
|
||||
EssOrg org = essOrgDao.findForUpdateOrNull(request.getOuId());
|
||||
if (org == null) {
|
||||
org = essSupport.createOrg(request);
|
||||
essOrgDao.save(org);
|
||||
}
|
||||
EssPerson person = getOrCreateOrgPerson(request);
|
||||
return new OrgAndPerson(org, person);
|
||||
}
|
||||
|
||||
// !! org and person
|
||||
|
||||
@BizTransactional
|
||||
public void addAuthorizedOrgPerson(OrgPerson orgPerson) {
|
||||
String subject = idbuilder() //
|
||||
.append(orgPerson.getOuId()) //
|
||||
.append(orgPerson.getPersonId()) //
|
||||
.build();
|
||||
essLogDao.log("personAuthorized", subject);
|
||||
EssPerson person = getOrCreateOrgPerson(orgPerson);
|
||||
essPersonDao.setOrgPersonState(person, EssPersonState.AUTHORIZED);
|
||||
log.info("add authorized person: {}", person);
|
||||
}
|
||||
|
||||
private EssPerson getOrCreateOrgPerson(OrgPerson orgPerson) {
|
||||
EssPerson essPerson = essPersonDao.find(orgPerson, true).orElse(null);
|
||||
if (essPerson == null) {
|
||||
essPerson = essSupport.createPerson(orgPerson);
|
||||
essPersonDao.save(essPerson);
|
||||
essPerson = essPersonDao.find(orgPerson, true).orElseThrow(InternalError::new);
|
||||
}
|
||||
return essPerson;
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void setOrgAuthorized(OrgPerson superAdmin) {
|
||||
essLogDao.log("orgAuthorized", superAdmin.getOuId(), "superAdminPersonId", superAdmin.getPersonId());
|
||||
essOrgDao.setOrgAuthorized(superAdmin);
|
||||
essLogDao.log("setOrgAuthorized", superAdmin.getOuId(), "superAdmin", superAdmin);
|
||||
log.info("set org authorized, superAdmin={}", superAdmin);
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void changeSuperAdmin(OrgPerson admin) {
|
||||
essOrgDao.changeSuperAdmin(admin);
|
||||
log.info("change super admin: {}", OrgPerson.toString(admin));
|
||||
}
|
||||
|
||||
public EssPerson getSuperAdminOrThrow(Long ouId) {
|
||||
EssPerson superAdmin = findSuperAdmin(ouId).orElse(null);
|
||||
BizAssertions.assertNotNull(superAdmin, "单位还未认证. 单位id={}", ouId);
|
||||
return superAdmin;
|
||||
}
|
||||
|
||||
public Optional<EssPerson> findSuperAdmin(Long ouId) {
|
||||
EssOrg org = findOrgOrNull(ouId);
|
||||
if (org == null)
|
||||
return Optional.empty();
|
||||
if (org.getSuperAdminPersonId() <= 0L)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(essPersonDao.findOrNull(ouId, org.getSuperAdminPersonId()));
|
||||
}
|
||||
|
||||
public EssOrg findOrgOrNull(Long ouId) {
|
||||
return essOrgDao.findOrNull(ouId);
|
||||
}
|
||||
|
||||
// !! seal
|
||||
|
||||
@BizTransactional
|
||||
public boolean maybeAddSeal(Long ouId, String essSealId, EssSealType type, String name) {
|
||||
EssSeal seal = essSealDao.findByEssSealId(essSealId).orElse(null);
|
||||
if (seal != null)
|
||||
return false;
|
||||
seal = new EssSeal();
|
||||
seal.setOuId(ouId);
|
||||
seal.setEssSealId(essSealId);
|
||||
seal.setName(name);
|
||||
seal.setState(EssSealState.CREATE);
|
||||
seal.setType(type);
|
||||
try {
|
||||
essSealDao.save(seal);
|
||||
log.info("add seal: {}", seal);
|
||||
return true;
|
||||
}
|
||||
catch (DuplicateKeyException ignored) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSealState(String essSealId, EssSealState state) {
|
||||
essSealDao.updateState(essSealId, state);
|
||||
log.info("update seal state: {}, {}", essSealId, state);
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void maybeAddPersonAndSetSealAuthorized(String essSealId, Long personId) {
|
||||
maybeAddSealPerson(essSealId, personId);
|
||||
essSealPersonDao.setPersonAuthorized(essSealId, personId);
|
||||
String subject = idbuilder().append(essSealId).append(personId).build();
|
||||
essLogDao.log("maybeAddPersonAndSetSealAuthorized", subject, "personId", personId);
|
||||
log.info("add seal authorization: essSealId={}, personId={}", essSealId, personId);
|
||||
}
|
||||
|
||||
public void setSealPersonAuthorizedBy(String essSealId, Long personId, Long authorizedByPersonId) {
|
||||
essSealPersonDao.setSealPersonAuthorizedBy(essSealId, personId, authorizedByPersonId);
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void removeSealAuthorization(String essSealId, Long personId) {
|
||||
maybeAddSealPerson(essSealId, personId);
|
||||
essSealPersonDao.removeSealAuthorization(essSealId, personId);
|
||||
String subject = idbuilder().append(essSealId).append(personId).build();
|
||||
essLogDao.log("removeSealAuthorization", subject, "personId", personId);
|
||||
log.info("remove seal authorization: essSealId={}, personId={}", essSealId, personId);
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public EssPerson addSealPerson(String essSealId, Long personId) {
|
||||
EssSeal seal = essSealDao.findByEssSealId(essSealId).orElse(null);
|
||||
BizAssertions.assertNotNull(seal, "印章不存在: {}", essSealId);
|
||||
//noinspection DataFlowIssue
|
||||
EssPerson essPerson = getOrCreateOrgPerson(OrgPersonInfo.create(seal.getOuId(), personId));
|
||||
maybeAddSealPerson(essSealId, personId);
|
||||
return essPerson;
|
||||
}
|
||||
|
||||
/**
|
||||
* should be called in transaction
|
||||
*/
|
||||
private void maybeAddSealPerson(String essSealId, Long personId) {
|
||||
EssSeal seal = essSealDao.findByEssSealId(essSealId).orElse(null);
|
||||
BizAssertions.assertNotNull(seal, "印章不存在: {}", essSealId);
|
||||
EssSealPerson savedSealPerson = essSealPersonDao.find(essSealId, personId, true).orElse(null);
|
||||
if (savedSealPerson != null)
|
||||
return;
|
||||
EssSealPerson sealPerson = new EssSealPerson();
|
||||
//noinspection DataFlowIssue
|
||||
sealPerson.setOuId(seal.getOuId());
|
||||
sealPerson.setEssSealId(essSealId);
|
||||
sealPerson.setPersonId(personId);
|
||||
sealPerson.setIsAuthorized(YesOrNo.NO);
|
||||
try {
|
||||
essSealPersonDao.save(sealPerson);
|
||||
}
|
||||
catch (DuplicateKeyException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@BizTransactional
|
||||
public void tryRemoveSealPerson(RemoveSealPersonRequest request) {
|
||||
EssSeal seal = essSealDao.findByEssSealId(request.getEssSealId()).orElse(null);
|
||||
BizAssertions.assertNotNull(seal, "印章不存在: {}", request.getEssSealId());
|
||||
//noinspection DataFlowIssue
|
||||
EssSealPerson sealPerson = essSealPersonDao.find(seal.getEssSealId(), request.getPersonId(), true).orElse(null);
|
||||
BizAssertions.assertNotNull(sealPerson, "印章人员不存在");
|
||||
//noinspection DataFlowIssue
|
||||
BizAssertions.assertTrue(!sealPerson.isAuthorized(), "请先取消授权再删除");
|
||||
essSealPersonDao.removeById(sealPerson.getId());
|
||||
log.info("remove seal person: {}", sealPerson);
|
||||
}
|
||||
|
||||
public void setOrgPersonResign(EssPerson person) {
|
||||
String subject = idbuilder() //
|
||||
.append(person.getOuId()) //
|
||||
.append(person.getPersonId()) //
|
||||
.build();
|
||||
essLogDao.log("personResign", subject);
|
||||
essPersonDao.setOrgPersonState(person, EssPersonState.RESIGNED);
|
||||
essSealPersonDao.deleteByPerson(person);
|
||||
log.info("set person resigned: {}", person);
|
||||
}
|
||||
|
||||
public void ensureOrgAuthorized(Long ouId, String message) {
|
||||
EssOrg org = findOrgOrNull(ouId);
|
||||
BizAssertions.assertTrue(org != null && org.isAuthorized(), message);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,181 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess;
|
||||
|
||||
import static java.util.stream.Collectors.groupingBy;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.basics.profiles.dto.basic.PersonProfileDto;
|
||||
import cn.axzo.nanopart.ess.api.domain.EssOrgAndSealInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.EssOrgInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.EssSealInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.EssSealPersonInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.PersonProfileInfo;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealState;
|
||||
import cn.axzo.nanopart.ess.api.request.GetOrgAuthStatesRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetPersonAuthStateRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetSealPersonRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetSealsRequest;
|
||||
import cn.axzo.nanopart.ess.api.response.GetOrgAuthStatesResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetPersonAuthStateResponse;
|
||||
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.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.entity.domain.OuAndPersonId;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.EssPersons;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.EssSupport;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.PersonProfiles;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class QueryService {
|
||||
|
||||
private final EssOrgDao essOrgDao;
|
||||
private final EssPersonDao essPersonDao;
|
||||
private final EssSealDao essSealDao;
|
||||
private final EssSealPersonDao essSealPersonDao;
|
||||
private final EssSupport essSupport;
|
||||
|
||||
public List<GetOrgAuthStatesResponse> getOrgAuthStates(GetOrgAuthStatesRequest request) {
|
||||
List<EssOrg> orgs = essOrgDao.getByOuIds(request.getOuIds());
|
||||
ArrayList<GetOrgAuthStatesResponse> responses = new ArrayList<>();
|
||||
for (Long ouId : request.getOuIds()) {
|
||||
GetOrgAuthStatesResponse response = new GetOrgAuthStatesResponse();
|
||||
responses.add(response);
|
||||
response.setOuId(ouId);
|
||||
response.setAuthorized(orgs.stream() //
|
||||
.filter(org -> org.getOuId().equals(ouId)) //
|
||||
.map(EssOrg::isAuthorized) //
|
||||
.findFirst() //
|
||||
.orElse(false));
|
||||
}
|
||||
return responses;
|
||||
}
|
||||
|
||||
public GetPersonAuthStateResponse getPersonAuthState(GetPersonAuthStateRequest request) {
|
||||
EssPerson person = essPersonDao.findOrNull(request);
|
||||
GetPersonAuthStateResponse response = new GetPersonAuthStateResponse();
|
||||
response.setAuthorized(person != null && person.isAuthorized());
|
||||
return response;
|
||||
}
|
||||
|
||||
public List<EssOrgAndSealInfo> getOrgEnabledSeals(GetSealsRequest request) {
|
||||
List<EssOrg> orgs = essOrgDao.lambdaQuery() //
|
||||
.in(EssOrg::getOuId, request.getOuIds()) //
|
||||
.list();
|
||||
Map<Long, List<EssSeal>> ouId2Seals = essSealDao.lambdaQuery() //
|
||||
.in(EssSeal::getOuId, request.getOuIds()) //
|
||||
.eq(EssSeal::getState, EssSealState.ENABLED).list().stream() //
|
||||
.collect(groupingBy(EssSeal::getOuId));
|
||||
Set<String> essSealIds = ouId2Seals.values().stream() //
|
||||
.flatMap(Collection::stream) //
|
||||
.map(EssSeal::getEssSealId) //
|
||||
.collect(toSet());
|
||||
Map<String, List<EssSealPerson>> essSealId2Persons = Collections.emptyMap();
|
||||
if (!essSealIds.isEmpty())
|
||||
essSealId2Persons = essSealPersonDao.lambdaQuery() //
|
||||
.in(EssSealPerson::getEssSealId, essSealIds).list().stream() //
|
||||
.collect(groupingBy(EssSealPerson::getEssSealId));
|
||||
HashSet<Long> personIds = new HashSet<>();
|
||||
essSealId2Persons.values().stream().flatMap(Collection::stream).forEach(sealPerson -> {
|
||||
personIds.add(sealPerson.getPersonId());
|
||||
personIds.add(sealPerson.getAuthorizedByPersonId());
|
||||
});
|
||||
// ess person
|
||||
EssPersons essPersons = EssPersons.wrap(essPersonDao.getByPersonIds(personIds));
|
||||
// person profile
|
||||
PersonProfiles personProfiles = PersonProfiles.wrap(
|
||||
essSupport.getPersonProfiles(Lists.newArrayList(personIds)));
|
||||
ArrayList<EssOrgAndSealInfo> essOrgAndSeals = new ArrayList<>();
|
||||
for (EssOrg org : orgs) {
|
||||
EssOrgAndSealInfo orgAndSeal = new EssOrgAndSealInfo();
|
||||
essOrgAndSeals.add(orgAndSeal);
|
||||
orgAndSeal.setOrg(BeanMapper.copyBean(org, EssOrgInfo.class));
|
||||
orgAndSeal.getOrg().setOrgAuthorized(org.isAuthorized());
|
||||
List<EssSeal> seals = ouId2Seals //
|
||||
.getOrDefault(org.getOuId(), Collections.emptyList()).stream() //
|
||||
.sorted(Comparator.comparingLong(BaseEntity::getId)) //
|
||||
.collect(toList());
|
||||
orgAndSeal.setSeals(BeanMapper.copyList(seals, EssSealInfo.class));
|
||||
for (EssSealInfo sealInfo : orgAndSeal.getSeals()) {
|
||||
List<EssSealPerson> persons = new ArrayList<>(
|
||||
essSealId2Persons.getOrDefault(sealInfo.getEssSealId(), Collections.emptyList()));
|
||||
persons.sort((p1, p2) -> -Long.compare(p1.getId(), p2.getId()));
|
||||
for (EssSealPerson sealPerson : persons)
|
||||
sealInfo.addSealPerson(createSealPersonInfo(essPersons, personProfiles, org, sealPerson));
|
||||
}
|
||||
}
|
||||
return essOrgAndSeals;
|
||||
}
|
||||
|
||||
public List<EssSealPersonInfo> getSealPersons(GetSealPersonRequest request) {
|
||||
List<EssSealPerson> sealPersons = essSealPersonDao.get(request.getEssSealId());
|
||||
if (sealPersons.isEmpty())
|
||||
return Collections.emptyList();
|
||||
HashSet<Long> personIds = new HashSet<>();
|
||||
sealPersons.forEach(sealPerson -> {
|
||||
personIds.add(sealPerson.getPersonId());
|
||||
personIds.add(sealPerson.getAuthorizedByPersonId());
|
||||
});
|
||||
EssPersons essPersons = EssPersons.wrap(essPersonDao.getByPersonIds(personIds));
|
||||
PersonProfiles personProfiles = PersonProfiles.wrap(
|
||||
essSupport.getPersonProfiles(Lists.newArrayList(personIds)));
|
||||
EssOrg org = essOrgDao.findOrNull(sealPersons.get(0).getOuId());
|
||||
BizAssertions.assertNotNull(org, "org not found, ouId={}", sealPersons.get(0).getOuId());
|
||||
ArrayList<EssSealPersonInfo> sealPersonsInfo = new ArrayList<>();
|
||||
for (EssSealPerson sealPerson : sealPersons)
|
||||
sealPersonsInfo.add(createSealPersonInfo(essPersons, personProfiles, org, sealPerson));
|
||||
return sealPersonsInfo;
|
||||
}
|
||||
|
||||
private EssSealPersonInfo createSealPersonInfo(EssPersons essPersons, PersonProfiles personProfiles, EssOrg org,
|
||||
EssSealPerson sealPerson) {
|
||||
EssPerson essPerson = essPersons.getOrThrow(
|
||||
OuAndPersonId.create(sealPerson.getOuId(), sealPerson.getPersonId()));
|
||||
EssSealPersonInfo sealPersonInfo = BeanMapper.copyBean(sealPerson, EssSealPersonInfo.class);
|
||||
sealPersonInfo.setSuperAdmin(org.isSuperAdmin(sealPerson.getPersonId()));
|
||||
sealPersonInfo.setSealAuthorized(sealPerson.isAuthorized());
|
||||
sealPersonInfo.setPersonAuthorized(essPerson.isAuthorized());
|
||||
sealPersonInfo.setAuthorizeTimeMs(
|
||||
sealPerson.getAuthorizeTime() == null ? null : sealPerson.getAuthorizeTime().getTime());
|
||||
BiConsumer<Long, PersonProfileInfo> builder = (personId, profileInfo) -> {
|
||||
PersonProfileDto profile = personProfiles.findOrNull(personId);
|
||||
if (profile == null)
|
||||
return;
|
||||
profileInfo.setPersonId(personId);
|
||||
profileInfo.setPersonName(profile.getRealName());
|
||||
profileInfo.setAvatar(profile.getAvatarUrl());
|
||||
};
|
||||
builder.accept(sealPerson.getPersonId(), sealPersonInfo.getSealPerson());
|
||||
if (sealPersonInfo.isSealAuthorized())
|
||||
builder.accept(sealPerson.getAuthorizedByPersonId(), sealPersonInfo.getAuthorizedByPerson());
|
||||
return sealPersonInfo;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,184 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.controller;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import cn.axzo.basics.common.BeanMapper;
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.nanopart.ess.api.EssApi;
|
||||
import cn.axzo.nanopart.ess.api.domain.EssOrgAndSealInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.EssSealPersonInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.EssContractInfo;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealPersonRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AssignSignUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.DownloadSingedContractPdfRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetContractDetailByContractIdRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetEmbedWebUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetOrgAuthStatesRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetPersonAuthStateRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetSealPersonRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetSealsRequest;
|
||||
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.SaveContractSnapshotRequest;
|
||||
import cn.axzo.nanopart.ess.api.response.AssignSignUrlResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateConsoleLoginUrlResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateContractByFileResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.DownloadSingedContractPdfResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetContractDetailByContractIdResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetEmbedWebUrlResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetOrgAuthStatesResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetPersonAuthStateResponse;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssContract;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssPerson;
|
||||
import cn.axzo.nanopart.ess.server.ess.ContractManager;
|
||||
import cn.axzo.nanopart.ess.server.ess.EssService;
|
||||
import cn.axzo.nanopart.ess.server.ess.OrgManager;
|
||||
import cn.axzo.nanopart.ess.server.ess.QueryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
class ApiController implements EssApi {
|
||||
|
||||
private final OrgManager orgManager;
|
||||
private final ContractManager contractManager;
|
||||
private final QueryService queryService;
|
||||
private final EssContractDao essContractDao;
|
||||
private final EssService essService;
|
||||
|
||||
@Override
|
||||
public ApiResult<List<GetOrgAuthStatesResponse>> getOrgAuthStates(GetOrgAuthStatesRequest request) {
|
||||
log.info("getOrgAuthStates request={}", request);
|
||||
return ApiResult.ok(queryService.getOrgAuthStates(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<GetPersonAuthStateResponse> getPersonAuthState(GetPersonAuthStateRequest request) {
|
||||
log.info("getPersonAuthState request={}", request);
|
||||
return ApiResult.ok(queryService.getPersonAuthState(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<CreateConsoleLoginUrlResponse> createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) {
|
||||
log.info("createConsoleLoginUrl request={}", request);
|
||||
CreateConsoleLoginUrlResponse response = new CreateConsoleLoginUrlResponse();
|
||||
response.setConsoleLoginUrl(essService.createConsoleLoginUrl(request));
|
||||
return ApiResult.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<GetEmbedWebUrlResponse> getEmbedWebUrl(GetEmbedWebUrlRequest request) {
|
||||
log.info("getEmbedWebUrl request={}", request);
|
||||
GetEmbedWebUrlResponse response = new GetEmbedWebUrlResponse();
|
||||
response.setEmbedWebUrl(essService.getEmbedWebUrl(request));
|
||||
return ApiResult.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<List<EssOrgAndSealInfo>> getOrgEnabledSeals(GetSealsRequest request) {
|
||||
log.info("getOrgEnabledSeals request={}", request);
|
||||
return ApiResult.ok(queryService.getOrgEnabledSeals(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<List<EssSealPersonInfo>> getSealPersons(GetSealPersonRequest request) {
|
||||
log.info("getSealPersons request={}", request);
|
||||
return ApiResult.ok(queryService.getSealPersons(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Boolean> addSealPerson(AddSealPersonRequest request) {
|
||||
log.info("addSealPerson request={}", request);
|
||||
EssPerson essPerson = orgManager.addSealPerson(request.getEssSealId(), request.getPersonId());
|
||||
if (essPerson.isAuthorized()) {
|
||||
AddSealAuthorizationRequest addSealAuthorizationRequest = new AddSealAuthorizationRequest();
|
||||
addSealAuthorizationRequest.setPersonId(essPerson.getPersonId());
|
||||
addSealAuthorizationRequest.setEssSealId(request.getEssSealId());
|
||||
addSealAuthorizationRequest.setOperatorPersonId(request.getOperatorPersonId());
|
||||
essService.essAddSealAuthorization(addSealAuthorizationRequest);
|
||||
return ApiResult.ok(true);
|
||||
}
|
||||
return ApiResult.ok(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> removeSealPerson(RemoveSealPersonRequest request) {
|
||||
log.info("removeSealPerson request={}", request);
|
||||
orgManager.tryRemoveSealPerson(request);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> addSealAuthorization(AddSealAuthorizationRequest request) {
|
||||
log.info("addSealAuthorization request={}", request);
|
||||
essService.essAddSealAuthorization(request);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> removeSealAuthorization(RemoveSealAuthorizationRequest request) {
|
||||
log.info("removeSealAuthorization request={}", request);
|
||||
essService.essRemoveSealAuthorization(request);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<CreateContractByFileResponse> createContractByFile(CreateContractByFileRequest request) {
|
||||
log.info("createContractByFile request={}", request);
|
||||
return ApiResult.ok(contractManager.createContractByFile(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<AssignSignUrlResponse> assignSignUrl(AssignSignUrlRequest request) {
|
||||
log.info("assignSignUrl request={}", request);
|
||||
AssignSignUrlResponse response = new AssignSignUrlResponse();
|
||||
response.setUrl(essService.assignSignUrl(request));
|
||||
return ApiResult.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<DownloadSingedContractPdfResponse> getContractPDFUrl(DownloadSingedContractPdfRequest request) {
|
||||
log.info("getContractPDFUrl request={}", request);
|
||||
DownloadSingedContractPdfResponse response = new DownloadSingedContractPdfResponse();
|
||||
response.setPdfUrl(essService.getContractPDFUrl(request.getEssContractId()));
|
||||
return ApiResult.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> saveContractSnapshot(SaveContractSnapshotRequest request) {
|
||||
log.info("saveContractSnapshot request={}", request);
|
||||
essService.saveContractSnapshot(request);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Void> revokeContract(RevokeContractRequest request) {
|
||||
log.info("revokeContract request={}", request);
|
||||
contractManager.revokeContract(request);
|
||||
return ApiResult.ok();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<GetContractDetailByContractIdResponse> getContractByContractId(
|
||||
GetContractDetailByContractIdRequest request) {
|
||||
log.info("getContractByContractId request={}", request);
|
||||
EssContract contract = essContractDao.getOrThrow(request.getEssContractId());
|
||||
GetContractDetailByContractIdResponse response = new GetContractDetailByContractIdResponse();
|
||||
response.setContract(BeanMapper.copyBean(contract, EssContractInfo.class));
|
||||
return ApiResult.ok(response);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,294 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.controller;
|
||||
|
||||
import static cn.axzo.nanopart.ess.api.request.CallbackRequest.ContractStateChanged;
|
||||
import static cn.axzo.nanopart.ess.api.request.CallbackRequest.OrgPersonJoin;
|
||||
import static cn.axzo.nanopart.ess.api.request.CallbackRequest.SealOperate;
|
||||
import static cn.axzo.nanopart.ess.server.utils.IdBuilder.idbuilder;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.math.NumberUtils;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.OccupiedSeal;
|
||||
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||
import cn.axzo.nanopart.ess.api.EssCallbackApi;
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.EssApproveDetail;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractApproveState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealType;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CallbackRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CallbackRequest.OrgAuthorizationFinish;
|
||||
import cn.axzo.nanopart.ess.api.request.CallbackRequest.SuperAdminChanged;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssLogDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssSealPersonDao;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssContract;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssLog;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssPerson;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
|
||||
import cn.axzo.nanopart.ess.server.ess.ContractManager;
|
||||
import cn.axzo.nanopart.ess.server.ess.EssClient;
|
||||
import cn.axzo.nanopart.ess.server.ess.EssService;
|
||||
import cn.axzo.nanopart.ess.server.ess.OrgManager;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.OrgOpenId;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.PersonOpenId;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.StringObject;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.EssSupport;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.OrgProfiles;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
* @see <a href="https://qian.tencent.com/developers/partner/callback_types_staffs">腾讯回调</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
class CallbackController implements EssCallbackApi, InitializingBean {
|
||||
|
||||
private final OrgManager orgManager;
|
||||
private final EssService essService;
|
||||
private final ContractManager contractManager;
|
||||
private final EssLogDao essLogDao;
|
||||
private final EssContractDao essContractDao;
|
||||
private final EssSealPersonDao essSealPersonDao;
|
||||
private final TransactionTemplate transactionTemplate;
|
||||
private final EssSupport essSupport;
|
||||
private final EssClient essClient;
|
||||
private final Map<CallbackType, CallbackHandler> handlers = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
// 企业开通电子签回调
|
||||
registerHandler(CallbackType.ORG_AUTHORIZATION_FINISH, request -> {
|
||||
OrgAuthorizationFinish result = request.readMsgData(OrgAuthorizationFinish.class);
|
||||
PersonOpenId superAdmin = PersonOpenId.parse(result.getProxyOperatorOpenId());
|
||||
if (result.isOpenSuccess()) {
|
||||
orgManager.addAuthorizedOrgPerson(superAdmin);
|
||||
orgManager.setOrgAuthorized(superAdmin);
|
||||
}
|
||||
return idbuilder() //
|
||||
.append(superAdmin.getOuId()) //
|
||||
.append(superAdmin.getPersonId()) //
|
||||
.build();
|
||||
});
|
||||
// 员工加入子企业的时候发送此通知
|
||||
registerHandler(CallbackType.ORG_PERSON_JOIN, request -> {
|
||||
PersonOpenId person = PersonOpenId.parse(request.readMsgData(OrgPersonJoin.class).getProxyOperatorOpenId());
|
||||
orgManager.addAuthorizedOrgPerson(person);
|
||||
// 自动授权
|
||||
for (EssSealPerson sealPerson : essSealPersonDao.getByPerson(person)) {
|
||||
AddSealAuthorizationRequest addSealAuthorizationRequest = new AddSealAuthorizationRequest();
|
||||
addSealAuthorizationRequest.setEssSealId(sealPerson.getEssSealId());
|
||||
addSealAuthorizationRequest.setPersonId(person.getPersonId());
|
||||
// 保留界面上的授权人
|
||||
addSealAuthorizationRequest.setOperatorPersonId(0L);
|
||||
try {
|
||||
essService.essAddSealAuthorization(addSealAuthorizationRequest);
|
||||
}
|
||||
catch (Exception e) {
|
||||
String subject = idbuilder() //
|
||||
.append(sealPerson.getEssSealId()) //
|
||||
.append(sealPerson.getPersonId()) //
|
||||
.build();
|
||||
essLogDao.log(e, "essAddSealAuthorization", subject);
|
||||
log.warn("add seal authorization failed", e);
|
||||
}
|
||||
}
|
||||
return idbuilder() //
|
||||
.append(person.getOuId()) //
|
||||
.append(person.getPersonId()) //
|
||||
.build();
|
||||
});
|
||||
// 印章回调
|
||||
registerHandler(CallbackType.SEAL_OPERATE, request -> {
|
||||
SealOperate operate = request.readMsgData(SealOperate.class);
|
||||
OrgOpenId ou = OrgOpenId.parse(operate.getProxyOrganizationOpenId());
|
||||
PersonOpenId operator = null;
|
||||
if (StringUtils.isNotBlank(operate.getProxyOperatorOpenId()))
|
||||
operator = PersonOpenId.parse(operate.getProxyOperatorOpenId());
|
||||
PersonOpenId authorized = StringUtils.isBlank(operate.getAuthorizedOperatorOpenId()) ? PersonOpenId.none()
|
||||
: PersonOpenId.parse(operate.getAuthorizedOperatorOpenId());
|
||||
String sealName = "";
|
||||
boolean isDelete = "Delete".equals(operate.getOperate());
|
||||
if (!isDelete && operator != null) {
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(operator.getOuId());
|
||||
OccupiedSeal sealInfo = essClient.getSealInfo(superAdmin, operate.getSealId());
|
||||
if (sealInfo != null)
|
||||
sealName = sealInfo.getSealName();
|
||||
}
|
||||
boolean sealCreated = orgManager.maybeAddSeal(ou.getOuId(), operate.getSealId(),
|
||||
EssSealType.fromEssCode(operate.getSealType()), sealName);
|
||||
// 1. 印章创建人会自动获得授权; 2. 避免miss create事件
|
||||
if (sealCreated && operator != null) {
|
||||
orgManager.maybeAddPersonAndSetSealAuthorized(operate.getSealId(), operator.getPersonId());
|
||||
orgManager.setSealPersonAuthorizedBy(operate.getSealId(), operator.getPersonId(),
|
||||
operator.getPersonId());
|
||||
}
|
||||
if (isDelete)
|
||||
orgManager.updateSealState(operate.getSealId(), EssSealState.DELETED);
|
||||
if ("Disable".equals(operate.getOperate()))
|
||||
orgManager.updateSealState(operate.getSealId(), EssSealState.DISABLED);
|
||||
if ("Enable".equals(operate.getOperate()))
|
||||
orgManager.updateSealState(operate.getSealId(), EssSealState.ENABLED);
|
||||
if ("Valid".equals(operate.getOperate())) {
|
||||
orgManager.maybeAddPersonAndSetSealAuthorized(operate.getSealId(), authorized.getPersonId());
|
||||
EssSealPerson savedPerson = essSealPersonDao //
|
||||
.find(operate.getSealId(), authorized.getPersonId()) //
|
||||
.orElseThrow(InternalError::new);
|
||||
boolean authorizedByPreset = savedPerson != null && savedPerson.getAuthorizedByPersonId() > 0;
|
||||
// 可能从控制台直接授权
|
||||
if (!authorizedByPreset && operator != null)
|
||||
orgManager.setSealPersonAuthorizedBy(operate.getSealId(), authorized.getPersonId(),
|
||||
operator.getPersonId());
|
||||
}
|
||||
if ("Invalid".equals(operate.getOperate()))
|
||||
orgManager.removeSealAuthorization(operate.getSealId(), authorized.getPersonId());
|
||||
return operate.getSealId();
|
||||
});
|
||||
// 合同回调
|
||||
registerHandler(CallbackType.CONTRACT_STATE_CHANGED, request -> {
|
||||
ContractStateChanged changes = request.readMsgData(ContractStateChanged.class);
|
||||
EssContractState state = EssContractState.fromEssCode(changes.getFlowStatus());
|
||||
if (state == null) {
|
||||
log.warn("unknown contract state: {}", changes.getFlowStatus());
|
||||
return changes.getFlowId();
|
||||
}
|
||||
List<Long> ouIds = changes.getFlowApproverInfo().stream() //
|
||||
.map(CallbackRequest.FlowApproverDetail::getProxyOrganizationOpenId) //
|
||||
.map(this::parseLong) //
|
||||
.filter(Objects::nonNull) //
|
||||
.collect(toList());
|
||||
OrgProfiles orgProfiles = OrgProfiles.wrap(essSupport.getOrgProfiles(ouIds));
|
||||
List<EssApproveDetail> approveDetails = changes.getFlowApproverInfo().stream().map(info -> {
|
||||
EssApproveDetail detail = new EssApproveDetail();
|
||||
if (StringUtils.isNotBlank(info.getProxyOperatorOpenId())) {
|
||||
PersonOpenId personOpenId = PersonOpenId.parse(info.getProxyOperatorOpenId());
|
||||
detail.setSignPerson(personOpenId.toOrgPersonInfo());
|
||||
}
|
||||
detail.setRecipientId(info.getRecipientId());
|
||||
detail.setState(EssContractApproveState.fromEssCode(info.getApproveStatus()));
|
||||
detail.setSignOrder(info.getSignOrder());
|
||||
detail.setApproveTimeMs(info.getApproveTime() * 1000);
|
||||
detail.setMessage(info.getApproveMessage());
|
||||
detail.setApproverDeadlineMs(info.getApproverDeadline() * 1000);
|
||||
detail.setPhoneNumber(info.getPhoneNumber());
|
||||
Long ouId = parseLong(info.getProxyOrganizationOpenId());
|
||||
OrganizationalUnitVO org = orgProfiles.find(ouId).orElse(null);
|
||||
if (org != null) {
|
||||
detail.setOuName(org.getName());
|
||||
detail.setOuId(org.getId());
|
||||
}
|
||||
return detail;
|
||||
}).collect(toList());
|
||||
EssContract contract = essContractDao.findOrNull(changes.getFlowId());
|
||||
if (contract == null && StringUtils.isNotBlank(changes.getCustomerData())) {
|
||||
JSONObject customData = StringObject.parse(changes.getCustomerData()).asJsonObject();
|
||||
contract = essContractDao.getById(customData.getLong(ContractManager.CONTRACT_ID));
|
||||
}
|
||||
if (contract == null) {
|
||||
log.warn("contract not found: {}", changes.getFlowId());
|
||||
}
|
||||
else {
|
||||
contractManager.updateContractState(contract, state, approveDetails, changes.getFlowMessage());
|
||||
essService.maybeScheduleDownloadContractPDF(contract, true);
|
||||
}
|
||||
return changes.getFlowId();
|
||||
});
|
||||
registerHandler(CallbackType.SUPER_ADMIN_CHANGED, request -> {
|
||||
SuperAdminChanged changes = request.readMsgData(SuperAdminChanged.class);
|
||||
PersonOpenId admin = PersonOpenId.parse(changes.getChangeToUserOpenId());
|
||||
orgManager.changeSuperAdmin(admin);
|
||||
return admin.getOuId();
|
||||
});
|
||||
}
|
||||
|
||||
private Long parseLong(String value) {
|
||||
if (StringUtils.isBlank(value) || !NumberUtils.isDigits(value))
|
||||
return null;
|
||||
return Long.parseLong(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<Object> callback(CallbackRequest request) {
|
||||
log.info("ess callback: {}", request);
|
||||
Object subject = null;
|
||||
CallbackType callbackType = CallbackType.parse(request.getMsgType()).orElse(null);
|
||||
CallbackHandler handler = callbackType == null ? null : handlers.get(callbackType);
|
||||
EssLog essLog = new EssLog();
|
||||
essLog.addLogContent("interested", handler != null);
|
||||
try {
|
||||
if (handler != null) {
|
||||
subject = transactionTemplate.execute(unused -> {
|
||||
try {
|
||||
return handler.handle(request);
|
||||
}
|
||||
catch (Exception e) {
|
||||
essLog.setError(e);
|
||||
log.warn("callback failed", e);
|
||||
// wrap exception to make it throw to yoke
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
log.info("ignore callback: {}", request);
|
||||
}
|
||||
return ApiResult.ok("success");
|
||||
}
|
||||
finally {
|
||||
String callbackTypeStr = callbackType == null ? "" : "[" + callbackType + "]";
|
||||
essLog.setContext(String.format("ess:callback:%s%s", request.getMsgType(), callbackTypeStr));
|
||||
essLog.setSubject(subject == null ? "" : String.valueOf(subject));
|
||||
essLog.addLogContent("request", request);
|
||||
essLogDao.save(essLog);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerHandler(CallbackType callbackType, CallbackHandler handler) {
|
||||
handlers.put(callbackType, handler);
|
||||
}
|
||||
|
||||
private interface CallbackHandler {
|
||||
Object handle(CallbackRequest request);
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
private enum CallbackType {
|
||||
ORG_AUTHORIZATION_FINISH("OrgOpenTsignBiz"),
|
||||
ORG_PERSON_JOIN("VerifyStaffInfo"),
|
||||
SEAL_OPERATE("OperateSeal"),
|
||||
CONTRACT_STATE_CHANGED("FlowStatusChange"),
|
||||
SUPER_ADMIN_CHANGED("SuperAdminChange");
|
||||
|
||||
final String msgType;
|
||||
|
||||
static Optional<CallbackType> parse(String msgType) {
|
||||
// @formatter:off
|
||||
return Arrays.stream(CallbackType.values())
|
||||
.filter(type -> type.msgType.equals(msgType))
|
||||
.findFirst();
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.controller;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelDescribeEmployeesResponse;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.Staff;
|
||||
|
||||
import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
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.BizAssertions;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController("essPrivateController")
|
||||
@RequiredArgsConstructor
|
||||
public class PrivateController {
|
||||
|
||||
private final OrgManager orgManager;
|
||||
private final EssClient essClient;
|
||||
|
||||
@PostMapping("/private/ess/getOrgPersons")
|
||||
public ApiResult<?> getOrgPersons(@RequestParam("ouId") Long ouId) {
|
||||
EssOrg org = orgManager.findOrgOrNull(ouId);
|
||||
BizAssertions.assertNotNull(org, "电子签单位不存在");
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(ouId);
|
||||
HashMap<String, Staff> staffs = new HashMap<>();
|
||||
long offset = 0L;
|
||||
while (true) {
|
||||
ChannelDescribeEmployeesResponse response = essClient.getOrgPerson(superAdmin, org, offset);
|
||||
if (response.getEmployees() == null || response.getEmployees().length == 0)
|
||||
break;
|
||||
offset = response.getOffset() + 1;
|
||||
for (Staff staff : response.getEmployees())
|
||||
staffs.put(staff.getOpenId(), staff);
|
||||
}
|
||||
return ApiResult.ok(staffs.values());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.server.entity.EssPerson;
|
||||
import cn.axzo.nanopart.ess.server.entity.domain.OuAndPersonId;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class EssPersons {
|
||||
|
||||
private final List<EssPerson> persons;
|
||||
|
||||
public static EssPersons wrap(List<EssPerson> persons) {
|
||||
return new EssPersons(persons);
|
||||
}
|
||||
|
||||
public EssPerson getOrThrow(Long personId) {
|
||||
EssPerson person = find(personId).orElse(null);
|
||||
BizAssertions.assertNotNull(person, "person not found, personId={}", personId);
|
||||
return person;
|
||||
}
|
||||
|
||||
public Optional<EssPerson> find(Long personId) {
|
||||
return persons.stream().filter(p -> p.getId().equals(personId)).findFirst();
|
||||
}
|
||||
|
||||
public EssPerson getOrThrow(OuAndPersonId ouAndPersonId) {
|
||||
EssPerson person = find(ouAndPersonId).orElse(null);
|
||||
BizAssertions.assertNotNull(person, "person not found, ouId={}, personId={}", ouAndPersonId.getOuId(),
|
||||
ouAndPersonId.getPersonId());
|
||||
return person;
|
||||
}
|
||||
|
||||
public Optional<EssPerson> find(OuAndPersonId ouAndPersonId) {
|
||||
return persons.stream().filter(p -> ouAndPersonId.is(p.getOuId(), p.getPersonId())).findFirst();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.server.entity.EssOrg;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssPerson;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class OrgAndPerson {
|
||||
private final EssOrg org;
|
||||
private final EssPerson person;
|
||||
}
|
||||
@ -0,0 +1,39 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class OrgOpenId {
|
||||
|
||||
private final Long ouId;
|
||||
|
||||
public static OrgOpenId ofPerson(OrgPerson person) {
|
||||
return create(person.getOuId());
|
||||
}
|
||||
|
||||
public static OrgOpenId create(Long ouId) {
|
||||
return new OrgOpenId(ouId);
|
||||
}
|
||||
|
||||
public static OrgOpenId parse(String openId) {
|
||||
return new OrgOpenId(Long.parseLong(openId));
|
||||
}
|
||||
|
||||
public String toOpenId() {
|
||||
return ouId + "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toOpenId();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,47 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class PersonOpenId implements OrgPerson {
|
||||
|
||||
private static final PersonOpenId NONE = create(0L, 0L);
|
||||
|
||||
private final Long ouId;
|
||||
private final Long personId;
|
||||
|
||||
public static PersonOpenId none() {
|
||||
return NONE;
|
||||
}
|
||||
|
||||
public static PersonOpenId create(OrgPerson person) {
|
||||
return create(person.getOuId(), person.getPersonId());
|
||||
}
|
||||
|
||||
public static PersonOpenId create(Long ouId, Long personId) {
|
||||
return new PersonOpenId(ouId, personId);
|
||||
}
|
||||
|
||||
public static PersonOpenId parse(String openId) {
|
||||
String[] split = openId.split("_");
|
||||
return new PersonOpenId(Long.parseLong(split[0]), Long.parseLong(split[1]));
|
||||
}
|
||||
|
||||
public String toOpenId() {
|
||||
return ouId + "_" + personId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return toOpenId();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSeal;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class SealAndPerson {
|
||||
private final EssSeal seal;
|
||||
private final EssSealPerson sealPerson;
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class SealPersons {
|
||||
|
||||
private final List<EssSealPerson> person;
|
||||
|
||||
public static SealPersons wrap(List<EssSealPerson> person) {
|
||||
return new SealPersons(person);
|
||||
}
|
||||
|
||||
public boolean containsPerson(Long personId) {
|
||||
return person.stream().anyMatch(p -> p.getPersonId().equals(personId));
|
||||
}
|
||||
|
||||
public Optional<EssSealPerson> find(Long ouId, Long personId) {
|
||||
return person.stream().filter(p -> p.getOuId().equals(ouId) && p.getPersonId().equals(personId)).findFirst();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.domain;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class StringObject {
|
||||
|
||||
private final JSONObject obj;
|
||||
|
||||
public static StringObject create() {
|
||||
return new StringObject(new JSONObject());
|
||||
}
|
||||
|
||||
public static StringObject parse(String jsonStr) {
|
||||
return new StringObject(JSONObject.parseObject(jsonStr));
|
||||
}
|
||||
|
||||
public JSONObject asJsonObject() {
|
||||
return obj;
|
||||
}
|
||||
|
||||
public StringObject put(String key, Object value) {
|
||||
obj.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return obj.toJSONString();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
package cn.axzo.nanopart.ess.server.ess.job;
|
||||
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.executor.XxlJobExecutor;
|
||||
import com.xxl.job.core.handler.IJobHandler;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@RestController
|
||||
public class JobHttpHandler {
|
||||
|
||||
@PostMapping("/jobs/{jobName}")
|
||||
ReturnT<String> exec(@PathVariable String jobName,
|
||||
@RequestBody(required = false) JSONObject paramObj) throws Exception {
|
||||
IJobHandler jobHandler = XxlJobExecutor.loadJobHandler(jobName);
|
||||
if (jobHandler == null)
|
||||
return new ReturnT<>(ReturnT.FAIL_CODE, String.format("找不到job: %s", jobName));
|
||||
return jobHandler.execute(paramObj == null ? null : paramObj.toJSONString());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.job;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.OccupiedSeal;
|
||||
import com.xxl.job.core.biz.model.ReturnT;
|
||||
import com.xxl.job.core.handler.annotation.XxlJob;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealState;
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssOrgDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssSealDao;
|
||||
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.ess.EssClient;
|
||||
import cn.axzo.nanopart.ess.server.ess.OrgManager;
|
||||
import cn.axzo.nanopart.ess.server.utils.RecordCursor;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@SuppressWarnings("unused")
|
||||
public class SyncSealNameJob {
|
||||
|
||||
private final OrgManager orgManager;
|
||||
private final EssOrgDao essOrgDao;
|
||||
private final EssSealDao essSealDao;
|
||||
private final EssClient essClient;
|
||||
|
||||
@XxlJob("syncSealNameJob")
|
||||
public ReturnT<String> execute(String s) {
|
||||
RecordCursor<EssOrg> cursor = new RecordCursor<>(EssOrg::getId,
|
||||
() -> essOrgDao.lambdaQuery().eq(EssOrg::getIsAuthorized, YesOrNo.YES));
|
||||
for (List<EssOrg> orgs : cursor) {
|
||||
for (EssOrg org : orgs) {
|
||||
EssPerson superAdmin = orgManager.findSuperAdmin(org.getOuId()).orElse(null);
|
||||
if (superAdmin == null) continue;
|
||||
for (EssSeal seal : essSealDao.getByOuId(org.getOuId())) {
|
||||
try {
|
||||
if (seal.getState() == EssSealState.DELETED)
|
||||
continue;
|
||||
OccupiedSeal sealInfo = essClient.getSealInfo(superAdmin, seal.getEssSealId());
|
||||
if (sealInfo == null) continue;
|
||||
essSealDao.updateSealName(seal.getEssSealId(), sealInfo.getSealName());
|
||||
log.info("update seal name success, sealId: {}, sealName: {}", seal.getEssSealId(), sealInfo.getSealName());
|
||||
} catch (Exception e) {
|
||||
log.warn("get seal info failed, sealId: {}", seal.getEssSealId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ReturnT.SUCCESS;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,50 @@
|
||||
|
||||
package cn.axzo.nanopart.ess.server.ess.mq;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
|
||||
import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
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 lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
*
|
||||
* IMPORTANT: 目前用的是visa注册的消费组
|
||||
*
|
||||
* @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.registerHandler(InternalMQEvent.ESS_CONTRACT_DOWNLOAD_PDF.getEventCode(), this);
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user