REQ-3581: 备份
This commit is contained in:
parent
880d65bb4d
commit
2939ec73ab
@ -4,28 +4,26 @@ import cn.axzo.framework.domain.web.result.ApiResult;
|
||||
import cn.axzo.nanopart.ess.api.domain.EssOrgAndSealInfo;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealPersonsRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AssignWeixinAppUrlByOrgRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.DownloadSingedContractPdfRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetContractDetailByBizCodeRequest;
|
||||
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.GetSealsRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetSignUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.RemoveSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.RemoveSealPersonRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
|
||||
import cn.axzo.nanopart.ess.api.response.AssignWeixinAppUrlByOrgResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateConsoleLoginUrlResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateContractResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateContractByFileResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.DownloadSingedContractPdfResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetContractDetailByBizCodeResponse;
|
||||
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.api.response.GetSignUrlResponse;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -68,7 +66,7 @@ public interface EssApi {
|
||||
@RequestBody @Valid GetEmbedWebUrlRequest request);
|
||||
|
||||
/**
|
||||
* 查询单位已启用的印章以及授权人员列表
|
||||
* 查询单位已启用的印章以及授权人员列表等等
|
||||
*/
|
||||
@PostMapping("api/ess/getOrgEnabledSeals")
|
||||
ApiResult<List<EssOrgAndSealInfo>> getOrgEnabledSeals(
|
||||
@ -103,21 +101,21 @@ public interface EssApi {
|
||||
@RequestBody @Valid RemoveSealAuthorizationRequest request);
|
||||
|
||||
/**
|
||||
* 创建合同
|
||||
* 通过文件创建合同
|
||||
*/
|
||||
@PostMapping("api/ess/createContract")
|
||||
ApiResult<CreateContractResponse> createContract(
|
||||
@RequestBody @Valid CreateContractRequest request);
|
||||
@PostMapping("api/ess/createContractByFile")
|
||||
ApiResult<CreateContractByFileResponse> createContractByFile(
|
||||
@RequestBody @Valid CreateContractByFileRequest request);
|
||||
|
||||
/**
|
||||
* 根据单位分配微信小程序签署链接, 有效期为5分钟
|
||||
* 获取签署链接, 有效期为5分钟
|
||||
*/
|
||||
@PostMapping("api/ess/assignWeixinAppUrlByOrg")
|
||||
ApiResult<AssignWeixinAppUrlByOrgResponse> assignWeixinAppUrlByOrg(
|
||||
@RequestBody @Valid AssignWeixinAppUrlByOrgRequest request);
|
||||
@PostMapping("api/ess/getContractSignUrl")
|
||||
ApiResult<GetSignUrlResponse> getContractSignUrl(
|
||||
@RequestBody @Valid GetSignUrlRequest request);
|
||||
|
||||
/**
|
||||
* 下载已签署的合同PDF. 下载链接有效期为5分钟
|
||||
* 下载合同PDF. 下载链接有效期为5分钟
|
||||
*/
|
||||
@PostMapping("api/ess/getContractPDFUrl")
|
||||
ApiResult<DownloadSingedContractPdfResponse> getContractPDFUrl(
|
||||
@ -133,15 +131,8 @@ public interface EssApi {
|
||||
/**
|
||||
* 获取合同详情, 通过合同id
|
||||
*/
|
||||
@PostMapping("api/ess/getContractDetailByContractId")
|
||||
ApiResult<GetContractDetailByContractIdResponse> getContractDetailByContractId(
|
||||
@PostMapping("api/ess/getContractByContractId")
|
||||
ApiResult<GetContractDetailByContractIdResponse> getContractByContractId(
|
||||
@RequestBody @Valid GetContractDetailByContractIdRequest request);
|
||||
|
||||
/**
|
||||
* 获取合同详情, 通过业务id
|
||||
*/
|
||||
@PostMapping("api/ess/getContractDetailByBizCode")
|
||||
ApiResult<GetContractDetailByBizCodeResponse> getContractDetailByBizCode(
|
||||
@RequestBody @Valid GetContractDetailByBizCodeRequest request);
|
||||
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -1,14 +1,17 @@
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.DynamicApproverProps;
|
||||
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;
|
||||
|
||||
@ -18,7 +21,7 @@ import static java.util.stream.Collectors.toSet;
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter @Getter
|
||||
public class CreateContractInfo {
|
||||
public abstract class CreateContractInfo {
|
||||
|
||||
/**
|
||||
* 合同名称
|
||||
@ -26,31 +29,25 @@ public class CreateContractInfo {
|
||||
@NotBlank(message = "contractName不能为空")
|
||||
private String contractName;
|
||||
|
||||
/**
|
||||
* 是否为动态签署人, 即在创建合同的时候不指定签署人, 而是在获取签署链接时指定签署人
|
||||
* dynamicApprover=true时,不需要指定Approver#signPerson
|
||||
* dynamicApprover=false时, 需要指定Approver#signPerson
|
||||
*/
|
||||
private boolean dynamicApprover;
|
||||
|
||||
/**
|
||||
* 动态签署人属性
|
||||
*/
|
||||
@Valid
|
||||
private DynamicApproverProps dynamicApproverProps;
|
||||
|
||||
/**
|
||||
* 合同签署方
|
||||
*/
|
||||
@Valid
|
||||
@NotEmpty
|
||||
@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;
|
||||
|
||||
/**
|
||||
@ -59,7 +56,7 @@ public class CreateContractInfo {
|
||||
private boolean signOrdered = false;
|
||||
|
||||
/**
|
||||
* 合同流程的签署截止时间,格式为Unix标准时间戳
|
||||
* 合同流程的签署截止时间,格式为Unix标准时间戳, 透传给腾讯电子签
|
||||
* 如果未设置签署截止时间,则默认为合同流程创建后的365天时截止
|
||||
* 如果在签署截止时间前未完成签署,则合同状态会变为已过期,导致合同作废。
|
||||
*/
|
||||
@ -67,6 +64,8 @@ public class CreateContractInfo {
|
||||
|
||||
@JsonIgnore
|
||||
public Set<Long> getApproverOuIds() {
|
||||
if (approvers == null)
|
||||
return Collections.emptySet();
|
||||
return approvers.stream()
|
||||
.map(Approver::getOuId)
|
||||
.collect(toSet());
|
||||
@ -1,27 +0,0 @@
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.ApproverAssignType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter @Getter
|
||||
public class DynamicApproverProps {
|
||||
|
||||
public static DynamicApproverProps defaultProps() {
|
||||
DynamicApproverProps props = new DynamicApproverProps();
|
||||
props.setAssignType(ApproverAssignType.NONE);
|
||||
return props;
|
||||
}
|
||||
|
||||
/**
|
||||
* 动态签署人的限制信息
|
||||
*/
|
||||
@NotNull(message = "assignType不能为空")
|
||||
private ApproverAssignType assignType = ApproverAssignType.NONE;
|
||||
|
||||
}
|
||||
@ -34,6 +34,11 @@ public class EssSealPersonInfo {
|
||||
*/
|
||||
private boolean isPersonAuthorized;
|
||||
|
||||
/**
|
||||
* 授权时间, unix时间戳
|
||||
*/
|
||||
private Long authorizeTimeMs;
|
||||
|
||||
/**
|
||||
* 是否已经认证(印章授权)
|
||||
*/
|
||||
|
||||
@ -0,0 +1,27 @@
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class OperatorInfo implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 发起方单位id
|
||||
*/
|
||||
@NotNull(message = "ouId不能为空")
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 发起方人员id
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
private Long personId;
|
||||
|
||||
}
|
||||
@ -1,5 +1,7 @@
|
||||
package cn.axzo.nanopart.ess.api.domain;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@ -9,4 +11,8 @@ public interface OrgPerson {
|
||||
|
||||
Long getPersonId();
|
||||
|
||||
static boolean equals(OrgPerson a, OrgPerson b) {
|
||||
return Objects.equals(a.getOuId(), b.getOuId())
|
||||
&& Objects.equals(a.getPersonId(), b.getPersonId());
|
||||
}
|
||||
}
|
||||
@ -8,8 +8,11 @@ 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.Max;
|
||||
import javax.validation.constraints.Min;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import java.util.List;
|
||||
|
||||
@ -18,10 +21,10 @@ import java.util.List;
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class Approver implements OrgPerson {
|
||||
public class Approver implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 签署方人员信息, 如果是动态签署人, 则不需要传入. 在获取签署链接时再指定签署人
|
||||
* 签署方人员信息, 如果是动态签署人, 则传null, 在获取签署链接时再指定签署人
|
||||
*/
|
||||
@Valid
|
||||
private OrgPersonInfo signPerson;
|
||||
@ -35,6 +38,7 @@ public class Approver implements OrgPerson {
|
||||
/**
|
||||
* 签署方在签署合同之前,需要强制阅读合同的时长,可指定为3秒至300秒之间的任意值
|
||||
*/
|
||||
@Range(min = 3, max = 300, message = "preReadTime必须在3-300之间")
|
||||
@NotNull(message = "preReadTime不能为空")
|
||||
private Long preReadTimeSeconds = 10L;
|
||||
|
||||
@ -46,7 +50,7 @@ public class Approver implements OrgPerson {
|
||||
/**
|
||||
* 扩展信息, 内部使用
|
||||
*/
|
||||
private JSONObject extension;
|
||||
private JSONObject internal;
|
||||
|
||||
public void setEssRecipientId(String essRecipientId) {
|
||||
getOrCreateExtension().put("essRecipientId", essRecipientId);
|
||||
@ -54,15 +58,20 @@ public class Approver implements OrgPerson {
|
||||
|
||||
@JsonIgnore @JSONField(serialize = false)
|
||||
public String getEssRecipientId() {
|
||||
if (extension == null) return null;
|
||||
return extension.getString("essRecipientId");
|
||||
if (internal == null)
|
||||
return null;
|
||||
return internal.getString("essRecipientId");
|
||||
}
|
||||
|
||||
@JsonIgnore @JSONField(serialize = false)
|
||||
public JSONObject getOrCreateExtension() {
|
||||
if (extension == null)
|
||||
extension = new JSONObject();
|
||||
return extension;
|
||||
if (internal == null)
|
||||
internal = new JSONObject();
|
||||
return internal;
|
||||
}
|
||||
|
||||
public boolean isSignPersonPresent() {
|
||||
return signPerson != null;
|
||||
}
|
||||
|
||||
@JsonIgnore @JSONField(serialize = false)
|
||||
@ -74,4 +83,5 @@ public class Approver implements OrgPerson {
|
||||
public Long getPersonId() {
|
||||
return signPerson == null ? 0L : signPerson.getPersonId();
|
||||
}
|
||||
|
||||
}
|
||||
@ -12,12 +12,12 @@ import lombok.Setter;
|
||||
public class EssApproveDetail {
|
||||
|
||||
/**
|
||||
* 签署人单位
|
||||
* 签署人单位, 动态签署人在没有签署的时候可能为空
|
||||
*/
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 签署人
|
||||
* 签署人, 动态签署人在没有签署的时候可能为空
|
||||
*/
|
||||
private Long personId;
|
||||
|
||||
@ -52,12 +52,12 @@ public class EssApproveDetail {
|
||||
private long approverDeadlineMs;
|
||||
|
||||
/**
|
||||
* 单位名称
|
||||
* 单位名称, 动态签署人在没有签署的时候可能为空
|
||||
*/
|
||||
private String ouName;
|
||||
|
||||
/**
|
||||
* 对应签署人的手机号
|
||||
* 对应签署人的手机号, 动态签署人在没有签署的时候可能为空
|
||||
*/
|
||||
private String phoneNumber;
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
package cn.axzo.nanopart.ess.api.domain.contract;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractState;
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -50,22 +49,12 @@ public class EssContractInfo {
|
||||
private EssContractState state;
|
||||
|
||||
/**
|
||||
* 是否为动态签署人
|
||||
*/
|
||||
private YesOrNo isDynamicApprover;
|
||||
|
||||
/**
|
||||
* 合并签署方信息(非动态签署人)
|
||||
* 合并签署方信息, 如果是动态签署, 里面的签署人信息可能为nul
|
||||
*/
|
||||
private List<Approver> approvers;
|
||||
|
||||
/**
|
||||
* 动态签署人信息
|
||||
*/
|
||||
private List<Approver> dynamicApprovers;
|
||||
|
||||
/**
|
||||
* 签署方的签署情况
|
||||
* 合同的签署方的签署情况
|
||||
*/
|
||||
private List<EssApproveDetail> approveDetails;
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.nanopart.ess.api.domain.contract;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -9,7 +10,7 @@ import javax.validation.constraints.NotNull;
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter @Getter
|
||||
public class OrgPersonInfo {
|
||||
public class OrgPersonInfo implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public enum ApproverAssignType {
|
||||
|
||||
// 一个子客一个用户盖章
|
||||
ONE_PERSON_PER_ORG,
|
||||
// 不做限制
|
||||
NONE
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
package cn.axzo.nanopart.ess.api.enums;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public enum Constraint {
|
||||
|
||||
// 一个子客只允许一个用户盖章
|
||||
ONE_PERSON_PER_ORG
|
||||
|
||||
}
|
||||
@ -4,6 +4,12 @@ import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@ -35,4 +41,10 @@ public enum EssContractState {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<EssContractState> collectFinalStates() {
|
||||
return Arrays.stream(values())
|
||||
.filter(EssContractState::isFinalState)
|
||||
.collect(toList());
|
||||
}
|
||||
}
|
||||
@ -3,6 +3,6 @@ package cn.axzo.nanopart.ess.api.enums;
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
public enum SignUrlType {
|
||||
public enum SignUrlEndpoint {
|
||||
PC, WEIXIN_APP
|
||||
}
|
||||
@ -12,7 +12,7 @@ import lombok.Setter;
|
||||
public class EssContractStateChangeMessage extends MqMessage {
|
||||
|
||||
/**
|
||||
* 合同信息
|
||||
* 合同信息, 处理签署详情时需要做幂等
|
||||
*/
|
||||
private EssContractInfo contract;
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssConsoleUrlEndpoint;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@ -11,7 +12,7 @@ import javax.validation.constraints.NotNull;
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class CreateConsoleLoginUrlRequest {
|
||||
public class CreateConsoleLoginUrlRequest implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 单位id
|
||||
@ -41,6 +42,6 @@ public class CreateConsoleLoginUrlRequest {
|
||||
/**
|
||||
* 调试参数, 不填
|
||||
*/
|
||||
private transient boolean checkOperator = true;
|
||||
private transient boolean essCheckLoginPerson = true;
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,32 @@
|
||||
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.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;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,9 @@
|
||||
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;
|
||||
|
||||
@ -10,8 +14,9 @@ import javax.validation.constraints.NotNull;
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter @Getter
|
||||
public class CreateContractRequest {
|
||||
@Setter
|
||||
@Getter
|
||||
public abstract class CreateContractRequest {
|
||||
|
||||
/**
|
||||
* 发起合同的应用或业务场景
|
||||
@ -20,40 +25,21 @@ public class CreateContractRequest {
|
||||
private String appCode;
|
||||
|
||||
/**
|
||||
* 业务编码
|
||||
* 业务编码, 最大长度200. 使用appCode和bizCode的合同不能重复
|
||||
* <p/>
|
||||
* 如果需要重复发起合同, 需要使用不同的bizCode, 建议: String.format("%s:%s", '真实业务编码', '序号或UUID')
|
||||
*/
|
||||
@NotBlank(message = "bizCode不能为空")
|
||||
private String bizCode;
|
||||
|
||||
/**
|
||||
* 发起方信息
|
||||
* 合同发起方信息
|
||||
*/
|
||||
@Valid
|
||||
@NotNull(message = "operator不能为空")
|
||||
private OperatorInfo operator;
|
||||
@NotNull(message = "creator不能为空")
|
||||
private OperatorInfo creator;
|
||||
|
||||
/**
|
||||
* 通过上传PDF发起合同
|
||||
*/
|
||||
@Valid
|
||||
@NotNull(message = "byFile不能为空")
|
||||
private CreateContractByFile byFile;
|
||||
|
||||
@Setter @Getter
|
||||
public static class OperatorInfo {
|
||||
|
||||
/**
|
||||
* 发起方单位id
|
||||
*/
|
||||
@NotNull(message = "ouId不能为空")
|
||||
private Long ouId;
|
||||
|
||||
/**
|
||||
* 发起方人员id
|
||||
*/
|
||||
@NotNull(message = "personId不能为空")
|
||||
private Long personId;
|
||||
|
||||
}
|
||||
@JsonIgnore @JSONField(serialize = false)
|
||||
public abstract CreateContractInfo getContract();
|
||||
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.enums.SignUrlType;
|
||||
import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -37,6 +37,6 @@ public class GetContractSignUrlRequest implements OrgPerson {
|
||||
* PC: 电脑端, WEIXIN_APP: 小程序
|
||||
*/
|
||||
@NotNull(message = "urlType不能为空")
|
||||
private SignUrlType urlType;
|
||||
private SignUrlEndpoint urlType;
|
||||
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
package cn.axzo.nanopart.ess.api.request;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.enums.SignUrlType;
|
||||
import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
@ -13,7 +13,7 @@ import javax.validation.constraints.NotNull;
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AssignWeixinAppUrlByOrgRequest implements OrgPerson {
|
||||
public class GetSignUrlRequest implements OrgPerson {
|
||||
|
||||
/**
|
||||
* 合同id
|
||||
@ -36,12 +36,15 @@ public class AssignWeixinAppUrlByOrgRequest implements OrgPerson {
|
||||
/**
|
||||
* PC: 电脑端, WEIXIN_APP: 小程序
|
||||
*/
|
||||
@NotNull(message = "urlType不能为空")
|
||||
private SignUrlType urlType;
|
||||
@NotNull(message = "endpoint不能为空")
|
||||
private SignUrlEndpoint endpoint;
|
||||
|
||||
/**
|
||||
* 签署方编号, 可以使用该编号指定动态签署方的信息, 或未指定将自动分配
|
||||
* 该编号在创建合同的时候会返回
|
||||
* 签署方编号, 可以使用该编号指定动态签署方的信息, 该编号在创建合同的时候会返回
|
||||
* <p/>
|
||||
* 如果在创建合同的时候存在任意没有指定具体签署人(Approver#signPersion)的情况下, 该字段必传
|
||||
* <p/>
|
||||
* 如果在创建合同的时候已经指定了所有的具体签署人(Approver#signPersion), 该字段可以不传
|
||||
*/
|
||||
private String recipientId;
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
@ -1,24 +0,0 @@
|
||||
package cn.axzo.nanopart.ess.api.response;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter @Getter
|
||||
public class CreateContractResponse {
|
||||
|
||||
/**
|
||||
* 合同id
|
||||
*/
|
||||
private String essContractId;
|
||||
|
||||
/**
|
||||
* 签署方编号, 可以使用该编号指定动态签署方的信息, 顺序和请求中的approvers一致
|
||||
*/
|
||||
private List<String> essRecipientIds;
|
||||
|
||||
}
|
||||
@ -8,7 +8,7 @@ import lombok.Setter;
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AssignWeixinAppUrlByOrgResponse {
|
||||
public class GetSignUrlResponse {
|
||||
|
||||
/**
|
||||
* 有效期为5分钟.
|
||||
@ -20,24 +20,21 @@ import java.util.Optional;
|
||||
@Repository("essContractDao")
|
||||
public class EssContractDao extends ServiceImpl<EssContractMapper, EssContract> {
|
||||
|
||||
public Optional<EssContract> findByBizCode(String appCode, String bizCode) {
|
||||
return lambdaQuery()
|
||||
.eq(EssContract::getAppCode, appCode)
|
||||
.eq(EssContract::getBizCode, bizCode)
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
public EssContract getOrThrow(String essContractId) {
|
||||
EssContract contract = find(essContractId).orElse(null);
|
||||
EssContract contract = findOrNull(essContractId);
|
||||
BizAssertions.assertNotNull(contract, "找不到合同信息, essContractId={}", essContractId);
|
||||
return contract;
|
||||
}
|
||||
|
||||
public Optional<EssContract> find(String essContractId) {
|
||||
return find(essContractId, false);
|
||||
public EssContract findOrNull(String essContractId) {
|
||||
return find(essContractId, false).orElse(null);
|
||||
}
|
||||
|
||||
public Optional<EssContract> find(String essContractId, boolean forUpdate) {
|
||||
public EssContract findForUpdateOrNull(String essContractId) {
|
||||
return find(essContractId, true).orElse(null);
|
||||
}
|
||||
|
||||
private Optional<EssContract> find(String essContractId, boolean forUpdate) {
|
||||
return lambdaQuery()
|
||||
.eq(EssContract::getEssContractId, essContractId)
|
||||
.last(forUpdate, "FOR UPDATE")
|
||||
@ -68,13 +65,6 @@ public class EssContractDao extends ServiceImpl<EssContractMapper, EssContract>
|
||||
.update();
|
||||
}
|
||||
|
||||
public void updateAssignedApprovers(EssContract contract) {
|
||||
lambdaUpdate()
|
||||
.eq(EssContract::getId, contract.getId())
|
||||
.set(EssContract::getAssignedApprovers, JSON.toJSONString(contract.getAssignedApprovers()))
|
||||
.update();
|
||||
}
|
||||
|
||||
public void setOssInfo(EssContract contract, String fileKey) {
|
||||
lambdaUpdate()
|
||||
.eq(EssContract::getId, contract.getId())
|
||||
|
||||
@ -2,6 +2,7 @@ package cn.axzo.nanopart.ess.server.dao;
|
||||
|
||||
import cn.axzo.nanopart.ess.server.entity.EssLog;
|
||||
import cn.axzo.nanopart.ess.server.mapper.EssLogMapper;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@ -10,4 +11,23 @@ import org.springframework.stereotype.Repository;
|
||||
*/
|
||||
@Repository("essLogDao")
|
||||
public class EssLogDao extends ServiceImpl<EssLogMapper, EssLog> {
|
||||
}
|
||||
|
||||
public void logRequest(String context, Object subject, Object request) {
|
||||
log(context, subject, "request", request);
|
||||
}
|
||||
|
||||
public void log(String context, Object subject, Object... logContents) {
|
||||
EssLog log = new EssLog();
|
||||
log.setContext(context);
|
||||
log.setSubject(String.valueOf(subject));
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -24,11 +24,15 @@ public class EssOrgDao extends ServiceImpl<EssOrgMapper, EssOrg> {
|
||||
return lambdaQuery().in(EssOrg::getOuId, ouIds).list();
|
||||
}
|
||||
|
||||
public Optional<EssOrg> find(Long ouId) {
|
||||
return find(ouId, false);
|
||||
public EssOrg findOrNull(Long ouId) {
|
||||
return find(ouId, false).orElse(null);
|
||||
}
|
||||
|
||||
public Optional<EssOrg> find(Long ouId, boolean forUpdate) {
|
||||
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")
|
||||
|
||||
@ -20,18 +20,18 @@ import java.util.Optional;
|
||||
public class EssPersonDao extends ServiceImpl<EssPersonMapper, EssPerson> {
|
||||
|
||||
public EssPerson findOrNull(OrgPerson person) {
|
||||
return find(person.getOuId(), person.getPersonId(), false).orElse(null);
|
||||
return findOrNull(person.getOuId(), person.getPersonId());
|
||||
}
|
||||
|
||||
public EssPerson findOrNull(Long ouId, Long personId) {
|
||||
return find(ouId, personId, false).orElse(null);
|
||||
}
|
||||
|
||||
public Optional<EssPerson> find(Long ouId, Long personId) {
|
||||
return find(ouId, personId, false);
|
||||
public Optional<EssPerson> find(OrgPerson person, boolean forUpdate) {
|
||||
return find(person.getOuId(), person.getPersonId(), forUpdate);
|
||||
}
|
||||
|
||||
public Optional<EssPerson> find(Long ouId, Long personId, boolean forUpdate) {
|
||||
private Optional<EssPerson> find(Long ouId, Long personId, boolean forUpdate) {
|
||||
return lambdaQuery()
|
||||
.eq(EssPerson::getOuId, ouId)
|
||||
.eq(EssPerson::getPersonId, personId)
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
package cn.axzo.nanopart.ess.server.dao;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealType;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSeal;
|
||||
import cn.axzo.nanopart.ess.server.mapper.EssSealMapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
@ -30,10 +27,4 @@ public class EssSealDao extends ServiceImpl<EssSealMapper, EssSeal> {
|
||||
.update();
|
||||
}
|
||||
|
||||
public List<EssSeal> getByOrgAndSealTypes(Long ouId, List<EssSealType> sealTypes) {
|
||||
return lambdaQuery()
|
||||
.eq(EssSeal::getOuId, ouId)
|
||||
.in(CollectionUtils.isNotEmpty(sealTypes), EssSeal::getType, sealTypes)
|
||||
.list();
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
package cn.axzo.nanopart.ess.server.dao;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.nanopart.ess.server.dao.domain.OuAndPersonId;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
|
||||
import cn.axzo.nanopart.ess.server.mapper.EssSealPersonMapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
@ -10,6 +9,7 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@ -26,6 +26,7 @@ public class EssSealPersonDao extends ServiceImpl<EssSealPersonMapper, EssSealPe
|
||||
.set(authorizedByPersonId != null && authorizedByPersonId > 0,
|
||||
EssSealPerson::getAuthorizedByPersonId, authorizedByPersonId)
|
||||
.set(EssSealPerson::getIsAuthorized, YesOrNo.YES)
|
||||
.set(EssSealPerson::getAuthorizeTime, new Date())
|
||||
.update();
|
||||
}
|
||||
|
||||
@ -37,13 +38,6 @@ public class EssSealPersonDao extends ServiceImpl<EssSealPersonMapper, EssSealPe
|
||||
.update();
|
||||
}
|
||||
|
||||
public Optional<EssSealPerson> findBySealAndPersonId(String essSealId, Long personId) {
|
||||
return lambdaQuery()
|
||||
.eq(EssSealPerson::getEssSealId, essSealId)
|
||||
.eq(EssSealPerson::getPersonId, personId)
|
||||
.oneOpt();
|
||||
}
|
||||
|
||||
public List<EssSealPerson> getBySealAndPersonIds(String essSealId, Collection<Long> personIds) {
|
||||
if (CollectionUtils.isEmpty(personIds))
|
||||
return Collections.emptyList();
|
||||
@ -53,19 +47,6 @@ public class EssSealPersonDao extends ServiceImpl<EssSealPersonMapper, EssSealPe
|
||||
.list();
|
||||
}
|
||||
|
||||
public List<EssSealPerson> getByOuAndPersonIds(Collection<OuAndPersonId> ouAndPersonIds) {
|
||||
if (CollectionUtils.isEmpty(ouAndPersonIds))
|
||||
return Collections.emptyList();
|
||||
return lambdaQuery()
|
||||
.nested(w -> {
|
||||
for (OuAndPersonId ouAndPersonId : ouAndPersonIds) {
|
||||
w.or().eq(EssSealPerson::getOuId, ouAndPersonId.getOuId())
|
||||
.eq(EssSealPerson::getPersonId, ouAndPersonId.getPersonId());
|
||||
}
|
||||
})
|
||||
.list();
|
||||
}
|
||||
|
||||
public Optional<EssSealPerson> find(String essSealId, Long personId) {
|
||||
return find(essSealId, personId, false);
|
||||
}
|
||||
|
||||
@ -3,20 +3,20 @@ 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.EssContractState;
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.nanopart.ess.api.enums.ApproverAssignType;
|
||||
import cn.axzo.nanopart.ess.server.entity.domain.AssignedApprovers;
|
||||
import cn.axzo.nanopart.ess.server.entity.domain.Assignment;
|
||||
import cn.axzo.pokonyan.config.mybatisplus.BaseEntity;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.nacos.common.utils.UuidUtils;
|
||||
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 javax.swing.table.DefaultTableCellRenderer;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
@ -34,7 +34,7 @@ public class EssContract extends BaseEntity<EssContract> {
|
||||
/**
|
||||
* 业务编码
|
||||
*/
|
||||
private String bizCode;
|
||||
private String bizCode = UuidUtils.generateUuid();
|
||||
|
||||
/**
|
||||
* 合同发起方单位id
|
||||
@ -67,11 +67,6 @@ public class EssContract extends BaseEntity<EssContract> {
|
||||
*/
|
||||
private EssContractState state;
|
||||
|
||||
/**
|
||||
* 是否为动态签署人
|
||||
*/
|
||||
private YesOrNo isDynamicApprover;
|
||||
|
||||
/**
|
||||
* 合并签署方信息
|
||||
*/
|
||||
@ -79,10 +74,10 @@ public class EssContract extends BaseEntity<EssContract> {
|
||||
private List<Approver> approvers;
|
||||
|
||||
/**
|
||||
* 动态签署人信息
|
||||
* 签署信息(扩展字段)
|
||||
*/
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private AssignedApprovers assignedApprovers;
|
||||
private Assignment assignment;
|
||||
|
||||
/**
|
||||
* 签署方的签署情况
|
||||
@ -101,27 +96,49 @@ public class EssContract extends BaseEntity<EssContract> {
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private RecordExt recordExt;
|
||||
|
||||
public boolean isDynamicApprover() {
|
||||
return isDynamicApprover.isYes();
|
||||
public Assignment getOrCreateAssignment() {
|
||||
if (assignment == null)
|
||||
assignment = new Assignment();
|
||||
return assignment;
|
||||
}
|
||||
|
||||
public boolean isOrgSigned(Long ouId) {
|
||||
if (approveDetails == null)
|
||||
return false;
|
||||
return approveDetails.stream()
|
||||
.anyMatch(detail -> detail.getOuId().equals(ouId));
|
||||
.anyMatch(detail -> ouId.equals(detail.getOuId()));
|
||||
}
|
||||
|
||||
public int preciseApproverSize() {
|
||||
return approvers.size();
|
||||
public int approverSize() {
|
||||
return approvers == null ? 0 : approvers.size();
|
||||
}
|
||||
|
||||
public Approver getPreciseApprover(Integer idx) {
|
||||
return approvers.get(idx);
|
||||
public Approver getApprover(Integer idx) {
|
||||
return approvers == null ? null : approvers.get(idx);
|
||||
}
|
||||
|
||||
public ApproverAssignType getAssignType() {
|
||||
return assignedApprovers == null ? null : assignedApprovers.getAssignType();
|
||||
public Optional<Approver> findApproverByRecipientId(String recipientId) {
|
||||
if (approvers == null)
|
||||
return Optional.empty();
|
||||
return approvers.stream()
|
||||
.filter(approver -> approver.getEssRecipientId().equals(recipientId))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public Constraint getAssignType() {
|
||||
return assignment == null ? null : assignment.getConstraint();
|
||||
}
|
||||
|
||||
public boolean isAllSignPersonPreset() {
|
||||
return approvers.stream().allMatch(Approver::isSignPersonPresent);
|
||||
}
|
||||
|
||||
public boolean isFinalState() {
|
||||
return state.isFinalState();
|
||||
}
|
||||
|
||||
public Constraint getConstraint() {
|
||||
return assignment == null ? null : assignment.getConstraint();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -48,6 +48,10 @@ public class EssOrg extends BaseEntity<EssOrg> {
|
||||
@TableField(typeHandler = FastjsonTypeHandler.class)
|
||||
private RecordExt recordExt;
|
||||
|
||||
public boolean isAuthorized() {
|
||||
return isAuthorized.isYes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JSON.toJSONString(this);
|
||||
|
||||
@ -10,6 +10,8 @@ import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@ -43,12 +45,21 @@ public class EssSealPerson extends BaseEntity<EssSealPerson> implements OrgPerso
|
||||
*/
|
||||
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);
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
package cn.axzo.nanopart.ess.server.entity.domain;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.enums.ApproverAssignType;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter
|
||||
@Getter
|
||||
public class AssignedApprovers {
|
||||
|
||||
private ApproverAssignType assignType;
|
||||
|
||||
private SignByOrg signByOrg = new SignByOrg();
|
||||
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
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;
|
||||
|
||||
}
|
||||
@ -1,74 +0,0 @@
|
||||
package cn.axzo.nanopart.ess.server.entity.domain;
|
||||
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Setter @Getter
|
||||
public class SignByOrg {
|
||||
|
||||
private final List<OrgRecipientId> recipientIds = new ArrayList<>();
|
||||
|
||||
public Approver getApproverOrThrow(List<Approver> approvers, String recipientId) {
|
||||
return approvers.stream()
|
||||
.filter(a -> a.getEssRecipientId().equals(recipientId))
|
||||
.findFirst()
|
||||
.orElseThrow(InternalError::new);
|
||||
}
|
||||
|
||||
public String assign(List<Approver> approvers, Long ouId, @Nullable String recipientId) {
|
||||
if (recipientId != null) {
|
||||
OrgRecipientId saved = findByRecipientId(recipientId).orElse(null);
|
||||
if (saved != null)
|
||||
BizAssertions.assertTrue(saved.getOuId().equals(ouId), "签署编号已被其它单位占用");
|
||||
else
|
||||
addRecipientId(ouId, recipientId);
|
||||
return recipientId;
|
||||
} else {
|
||||
OrgRecipientId assigned = findByOuId(ouId).orElse(null);
|
||||
if (assigned != null)
|
||||
return assigned.getRecipientId();
|
||||
for (Approver approver : approvers) {
|
||||
if (isRecipientIdUsed(approver.getEssRecipientId()))
|
||||
continue;
|
||||
addRecipientId(ouId, approver.getEssRecipientId());
|
||||
return approver.getEssRecipientId();
|
||||
}
|
||||
throw new ServiceException("签署编号已经用完, 无法将指定新的单位");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isRecipientIdUsed(String recipientId) {
|
||||
return findByRecipientId(recipientId).isPresent();
|
||||
}
|
||||
|
||||
public Optional<OrgRecipientId> findByRecipientId(String recipientId) {
|
||||
return recipientIds.stream()
|
||||
.filter(r -> r.getRecipientId().equals(recipientId))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public Optional<OrgRecipientId> findByOuId(Long ouId) {
|
||||
return recipientIds.stream()
|
||||
.filter(id -> id.getOuId().equals(ouId))
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
public void addRecipientId(Long ouId, String recipientId) {
|
||||
recipientIds.add(new OrgRecipientId() {{
|
||||
setOuId(ouId);
|
||||
setRecipientId(recipientId);
|
||||
}});
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,44 +1,30 @@
|
||||
package cn.axzo.nanopart.ess.server.ess;
|
||||
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.EssApproveDetail;
|
||||
import cn.axzo.nanopart.ess.api.enums.ApproverAssignType;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealType;
|
||||
import cn.axzo.nanopart.ess.api.request.AssignWeixinAppUrlByOrgRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateContractResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateContractByFileResponse;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssOrgDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssPersonDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssSealDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssSealPersonDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.domain.OuAndPersonId;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssLogDao;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssContract;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssOrg;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssPerson;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSeal;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.JsonObjectAsString;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.SealPersons;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.EssSupport;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.ContractSupport;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ApproverItem;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowByFilesResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static cn.axzo.nanopart.ess.server.utils.BizAssertions.fail;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
@ -53,90 +39,53 @@ public class ContractManager {
|
||||
|
||||
private final OrgManager orgManager;
|
||||
private final EssClient essClient;
|
||||
private final EssOrgDao essOrgDao;
|
||||
private final EssContractDao essContractDao;
|
||||
private final Broadcaster broadcaster;
|
||||
private final EssPersonDao essPersonDao;
|
||||
private final EssSealDao essSealDao;
|
||||
private final EssSealPersonDao essSealPersonDao;
|
||||
private final EssSupport essSupport;
|
||||
private final EssBroadcaster essBroadcaster;
|
||||
private final ContractSupport contractSupport;
|
||||
private final EssLogDao essLogDao;
|
||||
|
||||
public CreateContractResponse createContract(CreateContractRequest request) {
|
||||
checkPermission(request);
|
||||
EssContract contract = saveContract(request);
|
||||
@Transactional
|
||||
public CreateContractByFileResponse
|
||||
createContractByFile(CreateContractByFileRequest request) {
|
||||
essLogDao.logRequest("createContractByFile", request.getBizCode(), request);
|
||||
contractSupport.validateCreateContract(request.getContract());
|
||||
EssContract contract = contractSupport.saveContractByFile(request);
|
||||
try {
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(request.getOperator().getOuId());
|
||||
List<String> essFileIds = essClient.uploadDocument(
|
||||
superAdmin, request.getByFile().getBase64Files());
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(request.getCreator().getOuId());
|
||||
List<String> essFileIds = essClient.uploadDocument(superAdmin, request.getByFile().getBase64Files());
|
||||
ChannelCreateFlowByFilesResponse essResponse = essClient.createContractByFile(
|
||||
superAdmin, essFileIds, request.getByFile(),
|
||||
JsonObjectAsString.create().put(CONTRACT_ID, contract.getId()).toString());
|
||||
List<String> essRecipientIds = EssSupport.collectRecipientIds(essResponse.getApprovers());
|
||||
for (int i = 0; i < contract.preciseApproverSize(); i++) {
|
||||
Approver approver = contract.getPreciseApprover(i);
|
||||
approver.setEssRecipientId(essRecipientIds.get(i));
|
||||
}
|
||||
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());
|
||||
contract = essContractDao.getOrThrow(essResponse.getFlowId());
|
||||
broadcaster.fireContractStateChanged(contract);
|
||||
CreateContractResponse response = new CreateContractResponse();
|
||||
essBroadcaster.fireContractStateChanged(contract);
|
||||
CreateContractByFileResponse response = new CreateContractByFileResponse();
|
||||
response.setEssContractId(essResponse.getFlowId());
|
||||
response.setEssRecipientIds(essRecipientIds);
|
||||
return response;
|
||||
} catch (TencentCloudSDKException e) {
|
||||
} catch (TencentCloudSDKException | ServiceException e) {
|
||||
log.warn("创建合同失败", e);
|
||||
if (contract != null)
|
||||
essContractDao.removeById(contract.getId());
|
||||
throw new ServiceException("创建合同失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPermission(CreateContractRequest request) {
|
||||
BizAssertions.assertNotNull(request.getByFile(), "合同PDF文件不能为空");
|
||||
List<EssOrg> orgs = essOrgDao.getByOuIds(request.getByFile().getApproverOuIds());
|
||||
List<String> notAuthorizedOrgs = orgs.stream()
|
||||
.filter(i -> i.getIsAuthorized().isNo())
|
||||
.map(EssOrg::getOuName)
|
||||
.collect(toList());
|
||||
BizAssertions.assertEmpty(notAuthorizedOrgs,
|
||||
"创建合同失败. 以下单位还未认证: {}", JSON.toJSONString(notAuthorizedOrgs));
|
||||
SealPersons sealPersons = SealPersons.wrap(getApproverAsSealPersons(request));
|
||||
for (Approver approver : request.getByFile().getApprovers()) {
|
||||
if (approver.getSignPerson() == null) continue;
|
||||
EssSealPerson sealPerson = sealPersons.find(
|
||||
approver.getOuId(), approver.getPersonId()).orElse(null);
|
||||
BizAssertions.assertFalse(sealPerson == null || sealPerson.getIsAuthorized().isNo(),
|
||||
"创建合同失败. 部分签署人员没有印章授权, ouId={}, personId={}", approver.getOuId(), approver.getPersonId());
|
||||
}
|
||||
}
|
||||
|
||||
private List<EssSealPerson> getApproverAsSealPersons(CreateContractRequest request) {
|
||||
List<OuAndPersonId> ouAndPersonIds = request.getByFile().getApprovers().stream()
|
||||
.map(approver -> OuAndPersonId.create(approver.getOuId(), approver.getPersonId()))
|
||||
.distinct()
|
||||
.collect(toList());
|
||||
return essSealPersonDao.getByOuAndPersonIds(ouAndPersonIds);
|
||||
}
|
||||
|
||||
private EssContract saveContract(CreateContractRequest request) {
|
||||
try {
|
||||
EssContract contract = essSupport.createContract(request);
|
||||
essContractDao.save(contract);
|
||||
return contract;
|
||||
} catch (DuplicateKeyException e) {
|
||||
throw new ServiceException("创建合同失败. 重复的业务编号: " + request.getBizCode());
|
||||
throw fail("创建合同失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void revokeContract(RevokeContractRequest request) {
|
||||
essLogDao.logRequest("revokeContract", request.getEssContractId(), request);
|
||||
EssContract contract = essContractDao.getOrThrow(request.getEssContractId());
|
||||
BizAssertions.assertFalse(contract.getState().isFinalState(),
|
||||
"合同已是最终状态[{}], 无法撤销", contract.getState().getDescription());
|
||||
EssPerson contractCreator = getContractCreatorOrThrow(contract);
|
||||
essClient.revokeContract(contractCreator, contract.getEssContractId(), request.getReason());
|
||||
BizAssertions.assertFalse(contract.isFinalState(),
|
||||
"合同已是最终状态 {}, 无法撤销", contract.getState().getDescription());
|
||||
EssPerson superAdmin = getContractSuperAdmin(contract);
|
||||
essClient.revokeContract(superAdmin, contract.getEssContractId(), request.getReason());
|
||||
updateContractState(contract, EssContractState.CANCEL, null);
|
||||
}
|
||||
|
||||
@ -144,61 +93,19 @@ public class ContractManager {
|
||||
public void updateContractState(EssContract contract,
|
||||
EssContractState state,
|
||||
List<EssApproveDetail> approveDetails) {
|
||||
EssContract reloadContract = essContractDao
|
||||
.find(contract.getEssContractId(), true)
|
||||
.orElse(null);
|
||||
EssContract reloadContract = essContractDao.findForUpdateOrNull(contract.getEssContractId());
|
||||
BizAssertions.assertNotNull(reloadContract, "合同不存在: {}", contract.getEssContractId());
|
||||
//noinspection DataFlowIssue
|
||||
if (reloadContract.getState().isFinalState()) {
|
||||
log.warn("合同[{}]已是最终状态[{}], 无法更新状态",
|
||||
reloadContract.getEssContractId(),
|
||||
reloadContract.getState().getDescription());
|
||||
if (reloadContract.isFinalState()) {
|
||||
log.warn("合同[{}]已是最终状态[{}], 无法更新状态至{}",
|
||||
reloadContract.getEssContractId(), reloadContract.getState(), state);
|
||||
} else {
|
||||
essContractDao.updateState(contract, state, approveDetails);
|
||||
broadcaster.fireContractStateChanged(contract);
|
||||
essBroadcaster.fireContractStateChanged(contract);
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public String assignRecipientIdByOrg(AssignWeixinAppUrlByOrgRequest request) {
|
||||
EssContract contract = essContractDao.find(request.getEssContractId(), true).orElse(null);
|
||||
BizAssertions.assertNotNull(contract, "找不到合同信息, essContractId={}", request.getEssContractId());
|
||||
//noinspection DataFlowIssue
|
||||
BizAssertions.assertEquals(ApproverAssignType.ONE_PERSON_PER_ORG, contract.getAssignType(), "签署方式不正确");
|
||||
String recipientId = contract.getAssignedApprovers()
|
||||
.getSignByOrg()
|
||||
.assign(contract.getApprovers(), request.getOuId(), request.getRecipientId());
|
||||
Approver approver = contract.getAssignedApprovers()
|
||||
.getSignByOrg()
|
||||
.getApproverOrThrow(contract.getApprovers(), recipientId);
|
||||
checkApproverSeals(request, approver.getSealTypes());
|
||||
essContractDao.updateAssignedApprovers(contract);
|
||||
return recipientId;
|
||||
}
|
||||
|
||||
public void checkApproverSeals(OrgPerson person, List<EssSealType> sealTypes) {
|
||||
if (CollectionUtils.isEmpty(sealTypes))
|
||||
sealTypes = Arrays.stream(EssSealType.values()).collect(toList());
|
||||
List<EssSeal> seals = essSealDao
|
||||
.getByOrgAndSealTypes(person.getOuId(), sealTypes);
|
||||
BizAssertions.assertNotEmpty(seals, "单位没有指定类型的印章");
|
||||
boolean found = false;
|
||||
for (EssSeal seal : seals) {
|
||||
EssSealPerson sealPerson = essSealPersonDao
|
||||
.findBySealAndPersonId(seal.getEssSealId(), person.getPersonId())
|
||||
.orElse(null);
|
||||
found = sealPerson != null;
|
||||
if (found)
|
||||
break;
|
||||
}
|
||||
BizAssertions.assertTrue(found, "签署人员没有指定类型的印章");
|
||||
}
|
||||
|
||||
public EssPerson getContractCreatorOrThrow(EssContract contract) {
|
||||
EssPerson creator = essPersonDao.findOrNull(
|
||||
contract.getCreatorOuId(), contract.getCreatorPersonId());
|
||||
BizAssertions.assertNotNull(creator, "找不到合同发起人信息");
|
||||
return creator;
|
||||
public EssPerson getContractSuperAdmin(EssContract contract) {
|
||||
return orgManager.getSuperAdminOrThrow(contract.getCreatorOuId());
|
||||
}
|
||||
|
||||
}
|
||||
@ -16,14 +16,15 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
class Broadcaster {
|
||||
class EssBroadcaster {
|
||||
|
||||
private final EssContractDao essContractDao;
|
||||
protected final EventProducer<?> eventProducer;
|
||||
|
||||
void fireContractStateChanged(EssContract contract) {
|
||||
EssContract reloadContract = essContractDao
|
||||
.find(contract.getEssContractId()).orElse(null);
|
||||
EssContract reloadContract = essContractDao.findOrNull(contract.getEssContractId());
|
||||
if (reloadContract == null)
|
||||
return;
|
||||
EssContractStateChangeMessage message = new EssContractStateChangeMessage();
|
||||
message.setContract(BeanMapper.copyBean(reloadContract, EssContractInfo.class));
|
||||
eventProducer.send(Event.builder()
|
||||
@ -1,13 +1,12 @@
|
||||
package cn.axzo.nanopart.ess.server.ess;
|
||||
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
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.request.CreateContractInfo;
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssLogDao;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssLog;
|
||||
@ -35,7 +34,6 @@ 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.ChannelCreateOrganizationBatchSignUrlRequest;
|
||||
@ -51,7 +49,6 @@ 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.ProxyOrganizationOperator;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.SyncProxyOrganizationOperatorsRequest;
|
||||
@ -62,6 +59,7 @@ import com.tencentcloudapi.essbasic.v20210526.models.UserInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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;
|
||||
@ -81,6 +79,7 @@ import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static cn.axzo.nanopart.ess.server.ess.EssClient.Func.func;
|
||||
import static cn.axzo.nanopart.ess.server.utils.BizAssertions.fail;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
@ -104,8 +103,8 @@ public class EssClient implements InitializingBean {
|
||||
|
||||
public String createConsoleLoginUrl(EssOrg org, EssPerson person,
|
||||
EssConsoleUrlEndpoint endpoint,
|
||||
boolean checkOperator) {
|
||||
PersonProfileDto personProfile = essSupport.getPersonProfileOrThrow(person.getPersonId());
|
||||
boolean essCheckLoginPerson) {
|
||||
PersonProfileDto personProfile = essSupport.getPersonProfileOrThrow(person);
|
||||
CreateConsoleLoginUrlRequest request = new CreateConsoleLoginUrlRequest();
|
||||
request.setEndpoint(endpoint.getCode());
|
||||
request.setEndpoint(request.getEndpoint());
|
||||
@ -114,7 +113,7 @@ public class EssClient implements InitializingBean {
|
||||
if (props.isTestEnv())
|
||||
orgName = orgName.replaceAll("中国", "zhongguo");
|
||||
request.setProxyOrganizationName(orgName);
|
||||
if (checkOperator) {
|
||||
if (essCheckLoginPerson) {
|
||||
request.setProxyOperatorName(personProfile.getRealName());
|
||||
request.setProxyOperatorMobile(personProfile.getPhone());
|
||||
}
|
||||
@ -129,11 +128,11 @@ public class EssClient implements InitializingBean {
|
||||
return response.getConsoleUrl();
|
||||
}
|
||||
|
||||
public String getEmbedWebUrl(EssPerson superAdmin, EssEmbedType embedType, String businessId) {
|
||||
public String getEmbedWebUrl(EssPerson contextPerson, EssEmbedType embedType, String businessId) {
|
||||
if (embedType.isBusinessIdRequired())
|
||||
BizAssertions.assertNotBlank(businessId, "内嵌类型为{}时业务ID不能为空", embedType.name());
|
||||
ChannelCreateEmbedWebUrlRequest request = new ChannelCreateEmbedWebUrlRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setAgent(agent(contextPerson));
|
||||
request.setBusinessId(businessId);
|
||||
request.setEmbedType(embedType.getEssCode());
|
||||
request.setHiddenComponents(true);
|
||||
@ -211,28 +210,25 @@ public class EssClient implements InitializingBean {
|
||||
List<String> contractFileIds,
|
||||
CreateContractInfo contract,
|
||||
String customerData) throws TencentCloudSDKException {
|
||||
OrgProfiles orgProfiles = OrgProfiles.empty();
|
||||
PersonProfiles personProfiles = PersonProfiles.empty();
|
||||
if (!contract.isDynamicApprover()) {
|
||||
orgProfiles = OrgProfiles.wrap(essSupport
|
||||
.getOrgProfiles(contract.getApprovers().stream()
|
||||
.map(Approver::getOuId)
|
||||
.collect(toList())));
|
||||
personProfiles = PersonProfiles.wrap(essSupport
|
||||
.getPersonProfiles(contract.getApprovers().stream()
|
||||
.map(Approver::getPersonId)
|
||||
.collect(toList())));
|
||||
}
|
||||
OrgProfiles orgProfiles = OrgProfiles.wrap(essSupport
|
||||
.getOrgProfiles(contract.getApprovers().stream()
|
||||
.filter(Approver::isSignPersonPresent)
|
||||
.map(Approver::getOuId)
|
||||
.collect(toList())));
|
||||
PersonProfiles personProfiles = PersonProfiles.wrap(essSupport
|
||||
.getPersonProfiles(contract.getApprovers().stream()
|
||||
.filter(Approver::isSignPersonPresent)
|
||||
.map(Approver::getPersonId)
|
||||
.collect(toList())));
|
||||
ArrayList<FlowApproverInfo> approvers = new ArrayList<>();
|
||||
for (Approver approver : contract.getApprovers()) {
|
||||
FlowApproverInfo approverInfo = new FlowApproverInfo();
|
||||
approvers.add(approverInfo);
|
||||
if (contract.isDynamicApprover()) {
|
||||
if (approver.getSignPerson() == null) {
|
||||
ApproverOption approverOption = new ApproverOption();
|
||||
approverOption.setFillType(1L);
|
||||
approverInfo.setApproverOption(approverOption);
|
||||
} else {
|
||||
BizAssertions.assertNotNull(approver.getSignPerson(), "非动态签署人合同, 签署人不能为空");
|
||||
OrganizationalUnitVO orgProfile = orgProfiles.getOrThrow(approver.getOuId());
|
||||
PersonProfileDto personProfile = personProfiles.getOrThrow(approver.getPersonId());
|
||||
approverInfo.setName(personProfile.getRealName());
|
||||
@ -271,36 +267,9 @@ public class EssClient implements InitializingBean {
|
||||
.command(() -> manage.ChannelCreateFlowByFiles(request)));
|
||||
}
|
||||
|
||||
public void assignApprover(String essContractId,
|
||||
EssPerson contractCreator,
|
||||
OrgPerson approver,
|
||||
String recipientId) {
|
||||
OrganizationalUnitVO orgProfile = essSupport
|
||||
.getOrgProfileOrThrow(approver.getOuId());
|
||||
PersonProfileDto personProfile = essSupport
|
||||
.getPersonProfileOrThrow(approver.getPersonId());
|
||||
FillApproverInfo approverInfo = new FillApproverInfo();
|
||||
approverInfo.setRecipientId(recipientId);
|
||||
approverInfo.setApproverName(personProfile.getRealName());
|
||||
approverInfo.setApproverMobile(personProfile.getPhone());
|
||||
approverInfo.setOpenId(PersonOpenId.create(approver).toOpenId());
|
||||
approverInfo.setOrganizationName(orgProfile.getName());
|
||||
approverInfo.setOrganizationOpenId(OrgOpenId.ofPerson(approver).toOpenId());
|
||||
ChannelCreateFlowApproversRequest request = new ChannelCreateFlowApproversRequest();
|
||||
request.setAgent(agent(contractCreator));
|
||||
request.setFlowId(essContractId);
|
||||
request.setFillApproverType(1L);
|
||||
request.setApprovers(new FillApproverInfo[]{approverInfo});
|
||||
exec(func()
|
||||
.context("ChannelCreateFlowApprovers")
|
||||
.subject(essContractId)
|
||||
.request(request)
|
||||
.command(() -> manage.ChannelCreateFlowApprovers(request)));
|
||||
}
|
||||
|
||||
void revokeContract(EssPerson contractCreator, String essContractId, String reason) {
|
||||
void revokeContract(EssPerson superAdmin, String essContractId, String reason) {
|
||||
ChannelCancelFlowRequest request = new ChannelCancelFlowRequest();
|
||||
request.setAgent(agent(contractCreator));
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setFlowId(essContractId);
|
||||
request.setCancelMessage(reason);
|
||||
exec(func()
|
||||
@ -335,18 +304,20 @@ public class EssClient implements InitializingBean {
|
||||
return response.getSignUrl();
|
||||
}
|
||||
|
||||
public CreateSignUrlsResponse assignWeixinAppUrlByOrg(
|
||||
String essContractId, EssPerson creator,
|
||||
public CreateSignUrlsResponse getWeixinAppSignUrl(
|
||||
String essContractId, EssPerson superAdmin,
|
||||
OrgPerson signPerson, String recipientId) {
|
||||
CreateSignUrlsRequest request = new CreateSignUrlsRequest();
|
||||
request.setAgent(agent(creator));
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setFlowIds(new String[]{essContractId});
|
||||
request.setOpenId(PersonOpenId.create(signPerson).toOpenId());
|
||||
request.setOrganizationOpenId(OrgOpenId.ofPerson(signPerson).toOpenId());
|
||||
request.setRecipientIds(new String[]{recipientId});
|
||||
request.setGenerateType("RECIPIENT");
|
||||
if (StringUtils.isNotBlank(recipientId)) {
|
||||
request.setRecipientIds(new String[]{recipientId});
|
||||
request.setGenerateType("RECIPIENT");
|
||||
}
|
||||
return exec(func()
|
||||
.context("CreateSignUrls:assignWeixinAppUrlByOrg")
|
||||
.context("CreateSignUrls")
|
||||
.subject(essContractId)
|
||||
.request(request)
|
||||
.command(() -> manage.CreateSignUrls(request)));
|
||||
@ -375,7 +346,7 @@ public class EssClient implements InitializingBean {
|
||||
.command(() -> manage.SyncProxyOrganizationOperators(request)));
|
||||
}
|
||||
|
||||
public ChannelDescribeEmployeesResponse getEmployees(EssPerson superAdmin, EssOrg org, Long offset) {
|
||||
public ChannelDescribeEmployeesResponse getOrgPerson(EssPerson superAdmin, EssOrg org, Long offset) {
|
||||
ChannelDescribeEmployeesRequest request = new ChannelDescribeEmployeesRequest();
|
||||
request.setAgent(agent(superAdmin));
|
||||
request.setOffset(offset);
|
||||
@ -417,7 +388,7 @@ public class EssClient implements InitializingBean {
|
||||
try {
|
||||
return call(builder);
|
||||
} catch (TencentCloudSDKException e) {
|
||||
throw new ServiceException(String.format("腾讯返回: %s", e.getMessage()), e);
|
||||
throw fail(e, String.format("腾讯返回: %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,16 +1,18 @@
|
||||
package cn.axzo.nanopart.ess.server.ess;
|
||||
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
import cn.axzo.nanopart.ess.api.enums.ApproverAssignType;
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
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.EssContext;
|
||||
import cn.axzo.nanopart.ess.api.enums.SignUrlType;
|
||||
import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AssignWeixinAppUrlByOrgRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetEmbedWebUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetSignUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.RemoveSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.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;
|
||||
@ -21,6 +23,7 @@ import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.OrgAndPerson;
|
||||
import cn.axzo.nanopart.ess.server.ess.domain.SealAndPerson;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.EssProps;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.EssSupport;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.OssService;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsResponse;
|
||||
@ -29,6 +32,11 @@ import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static cn.axzo.nanopart.ess.server.utils.BizAssertions.fail;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@ -45,12 +53,15 @@ public class EssService {
|
||||
private final EssPersonDao essPersonDao;
|
||||
private final EssProps essProps;
|
||||
private final OssService ossService;
|
||||
private final EssLogDao essLogDao;
|
||||
private final EssSupport essSupport;
|
||||
|
||||
public String createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) {
|
||||
essLogDao.logRequest("createConsoleLoginUrl", request.getPersonId(), request);
|
||||
OrgAndPerson orgAndPerson = orgManager.createConsoleLoginUrl(request);
|
||||
return essClient.createConsoleLoginUrl(
|
||||
orgAndPerson.getOrg(), orgAndPerson.getPerson(),
|
||||
request.getEndpoint(), request.isCheckOperator());
|
||||
request.getEndpoint(), request.isEssCheckLoginPerson());
|
||||
}
|
||||
|
||||
public String getEmbedWebUrl(GetEmbedWebUrlRequest request) {
|
||||
@ -58,18 +69,19 @@ public class EssService {
|
||||
if (request.getEmbedType().getEssContext() == EssContext.CONTRACT) {
|
||||
BizAssertions.assertNotNull(request.getBusinessId(), "合同ID不能为空");
|
||||
EssContract contract = essContractDao.getOrThrow(request.getBusinessId());
|
||||
contextPerson = contractManager.getContractCreatorOrThrow(contract);
|
||||
contextPerson = contractManager.getContractSuperAdmin(contract);
|
||||
} else if (request.getEmbedType().getEssContext() == EssContext.SEAL) {
|
||||
BizAssertions.assertNotNull(request.getBusinessId(), "印章ID不能为空");
|
||||
contextPerson = orgManager.getSuperAdminOrThrow(request.getOuId());
|
||||
} else {
|
||||
return null;
|
||||
throw fail("不支持的嵌入类型: {}", request.getEmbedType());
|
||||
}
|
||||
return essClient.getEmbedWebUrl(
|
||||
contextPerson, request.getEmbedType(), request.getBusinessId());
|
||||
}
|
||||
|
||||
public void essAddSealAuthorization(AddSealAuthorizationRequest request) {
|
||||
essLogDao.logRequest("essAddSealAuthorization", request.getPersonId(), request);
|
||||
SealAndPerson sealAndPerson = getSealAndPersonOrThrow(request);
|
||||
EssSealPerson sealPerson = sealAndPerson.getSealPerson();
|
||||
if (sealPerson.getIsAuthorized().isYes())
|
||||
@ -83,6 +95,7 @@ public class EssService {
|
||||
}
|
||||
|
||||
public void essRemoveSealAuthorization(RemoveSealAuthorizationRequest request) {
|
||||
essLogDao.logRequest("essRemoveSealAuthorization", request.getPersonId(), request);
|
||||
SealAndPerson sealAndPerson = getSealAndPersonOrThrow(request);
|
||||
if (sealAndPerson.getSealPerson().getIsAuthorized().isNo())
|
||||
return;
|
||||
@ -102,35 +115,48 @@ public class EssService {
|
||||
return new SealAndPerson(seal, sealPerson);
|
||||
}
|
||||
|
||||
public String assignWeixinAppUrlByOrg(AssignWeixinAppUrlByOrgRequest request) {
|
||||
public String getContractSignUrl(GetSignUrlRequest request) {
|
||||
essLogDao.logRequest("getContractSignUrl", request.getEssContractId(), request);
|
||||
EssPerson signPerson = essPersonDao.findOrNull(request);
|
||||
BizAssertions.assertNotNull(signPerson, "当前签署人员未加入单位, 无法签署");
|
||||
EssContract contract = essContractDao.getOrThrow(request.getEssContractId());
|
||||
BizAssertions.assertTrue(contract.isDynamicApprover(), "合同不支持动态签署");
|
||||
String recipientId;
|
||||
if (contract.getAssignedApprovers().getAssignType() == ApproverAssignType.ONE_PERSON_PER_ORG) {
|
||||
BizAssertions.assertFalse(contract.isFinalState(),
|
||||
"合同已是最终状态 {}, 无法签署", contract.getState());
|
||||
if (contract.getConstraint() == Constraint.ONE_PERSON_PER_ORG)
|
||||
BizAssertions.assertFalse(contract.isOrgSigned(request.getOuId()), "该单位已签署, 无法再次签署");
|
||||
recipientId = contractManager.assignRecipientIdByOrg(request);
|
||||
} else {
|
||||
throw new ServiceException(String.format("暂不支持的动态签署类型: %s", contract.getAssignedApprovers().getAssignType()));
|
||||
Function<String, String> signUrlFun = recipientId -> {
|
||||
EssPerson superAdmin = contractManager.getContractSuperAdmin(contract);
|
||||
CreateSignUrlsResponse essResponse = essClient.getWeixinAppSignUrl(
|
||||
request.getEssContractId(), superAdmin, request, recipientId);
|
||||
SignUrlInfo signUrlInfo = essResponse.getSignUrlInfos()[0];
|
||||
return request.getEndpoint() == SignUrlEndpoint.PC
|
||||
? signUrlInfo.getSignQrcodeUrl()
|
||||
: signUrlInfo.getSignUrl();
|
||||
};
|
||||
if (contract.isAllSignPersonPreset())
|
||||
return signUrlFun.apply(null);
|
||||
BizAssertions.assertFalse(StringUtils.isBlank(request.getRecipientId()),
|
||||
"存在动态签署人的情况下, recipientId不能为空");
|
||||
Approver approver = contract
|
||||
.findApproverByRecipientId(request.getRecipientId())
|
||||
.orElse(null);
|
||||
BizAssertions.assertNotNull(approver, "无效的签署编号: {}", request.getRecipientId());
|
||||
//noinspection DataFlowIssue
|
||||
if (approver.getSignPerson() != null) {
|
||||
BizAssertions.assertTrue(OrgPerson.equals(approver.getSignPerson(), request), "签署人员不匹配");
|
||||
return signUrlFun.apply(null);
|
||||
}
|
||||
EssPerson creator = contractManager.getContractCreatorOrThrow(contract);
|
||||
CreateSignUrlsResponse essResponse = essClient.assignWeixinAppUrlByOrg(
|
||||
request.getEssContractId(), creator, request, recipientId);
|
||||
SignUrlInfo signUrlInfo = essResponse.getSignUrlInfos()[0];
|
||||
return request.getUrlType() == SignUrlType.PC
|
||||
? signUrlInfo.getSignQrcodeUrl()
|
||||
: signUrlInfo.getSignUrl();
|
||||
return signUrlFun.apply(request.getRecipientId());
|
||||
}
|
||||
|
||||
public String getContractPDFUrl(String essContractId) {
|
||||
EssContract contract = essContractDao.getOrThrow(essContractId);
|
||||
if (essProps.isDownloadContractFromOss()
|
||||
&& contract.getState().isFinalState()
|
||||
&& StringUtils.isNotBlank(contract.getOssFileKey())) {
|
||||
return ossService.getOssUrl(contract.getOssFileKey());
|
||||
}
|
||||
ossService.maybeDownloadToOss(contract, () -> getContractPDFUrlFromEss(contract));
|
||||
maybeUploadContractToOss(contract.getEssContractId(),
|
||||
() -> getContractPDFUrlFromEss(contract));
|
||||
return getContractPDFUrlFromEss(contract);
|
||||
}
|
||||
|
||||
@ -138,4 +164,17 @@ public class EssService {
|
||||
EssPerson creator = orgManager.getSuperAdminOrThrow(contract.getCreatorOuId());
|
||||
return essClient.getContractPDFUrl(creator, contract.getEssContractId());
|
||||
}
|
||||
|
||||
public void maybeUploadContractToOss(String essContractId, Supplier<String> essPdfUrl) {
|
||||
essSupport.asyncExec(() -> {
|
||||
EssContract effectiveContract = essContractDao.findOrNull(essContractId);
|
||||
if (!effectiveContract.isFinalState()
|
||||
|| StringUtils.isNotBlank(effectiveContract.getOssFileKey()))
|
||||
return;
|
||||
String fileName = String.format("%s.pdf", effectiveContract.getContractName());
|
||||
String fileKey = ossService.uploadToOss(essPdfUrl.get(), fileName);
|
||||
essContractDao.setOssInfo(effectiveContract, fileKey);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
package cn.axzo.nanopart.ess.server.ess;
|
||||
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssPersonState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealState;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssSealType;
|
||||
@ -50,34 +51,33 @@ public class OrgManager {
|
||||
|
||||
@Transactional
|
||||
public OrgAndPerson createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) {
|
||||
EssOrg org = essOrgDao.find(request.getOuId(), true).orElse(null);
|
||||
EssOrg org = essOrgDao.findForUpdateOrNull(request.getOuId());
|
||||
if (org == null) {
|
||||
org = essSupport.createOrg(request);
|
||||
essOrgDao.save(org);
|
||||
}
|
||||
EssPerson person = getOrCreateOrgPerson(request.getOuId(), request.getPersonId());
|
||||
EssPerson person = getOrCreateOrgPerson(request);
|
||||
return new OrgAndPerson(org, person);
|
||||
}
|
||||
|
||||
// !! org and person
|
||||
|
||||
@Transactional
|
||||
public void addAuthorizedOrgPerson(Long ouId, Long personId) {
|
||||
EssPerson person = getOrCreateOrgPerson(ouId, personId);
|
||||
public void addAuthorizedOrgPerson(OrgPerson orgPerson) {
|
||||
EssPerson person = getOrCreateOrgPerson(orgPerson);
|
||||
essPersonDao.setState(person, EssPersonState.AUTHORIZED);
|
||||
log.info("add authorized person: {}", person);
|
||||
}
|
||||
|
||||
private EssPerson getOrCreateOrgPerson(Long ouId, Long personId) {
|
||||
EssPerson person = essPersonDao
|
||||
.find(ouId, personId, true).orElse(null);
|
||||
if (person == null) {
|
||||
person = essSupport.createPerson(ouId, personId);
|
||||
essPersonDao.save(person);
|
||||
person = essPersonDao.find(ouId, personId, true)
|
||||
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 person;
|
||||
return essPerson;
|
||||
}
|
||||
|
||||
public void setOrgAuthorized(Long ouId, Long authorizePersonId) {
|
||||
@ -90,14 +90,13 @@ public class OrgManager {
|
||||
|
||||
public EssPerson getSuperAdminOrThrow(Long ouId) {
|
||||
EssPerson superAdmin = findSuperAdmin(ouId).orElse(null);
|
||||
BizAssertions.assertNotNull(superAdmin, "单位还未认证: {}", ouId);
|
||||
BizAssertions.assertNotNull(superAdmin, "单位还未认证");
|
||||
return superAdmin;
|
||||
}
|
||||
|
||||
Optional<EssPerson> findSuperAdmin(Long ouId) {
|
||||
EssOrg org = essOrgDao.find(ouId).orElse(null);
|
||||
BizAssertions.assertNotNull(org, "单位不存在: {}", ouId);
|
||||
//noinspection DataFlowIssue
|
||||
EssOrg org = essOrgDao.findOrNull(ouId);
|
||||
BizAssertions.assertNotNull(org, "单位不存在");
|
||||
if (org.getSuperAdminPersonId() <= 0L)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(essPersonDao.findOrNull(ouId, org.getSuperAdminPersonId()));
|
||||
|
||||
@ -5,7 +5,10 @@ import cn.axzo.framework.rocketmq.Event;
|
||||
import cn.axzo.framework.rocketmq.EventConsumer;
|
||||
import cn.axzo.framework.rocketmq.EventHandler;
|
||||
import cn.axzo.maokai.api.domain.event.user.OrgUserStatusChangedEvent;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssLogDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssOrgDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssPersonDao;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssOrg;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssPerson;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@ -38,7 +41,9 @@ public class PersonResignListener extends BaseListener
|
||||
private final EventConsumer eventConsumer;
|
||||
private final EssClient essClient;
|
||||
private final OrgManager orgManager;
|
||||
private final EssOrgDao essOrgDao;
|
||||
private final EssPersonDao essPersonDao;
|
||||
private final EssLogDao essLogDao;
|
||||
|
||||
@Override
|
||||
public void onMessage(MessageExt message) {
|
||||
@ -57,11 +62,19 @@ public class PersonResignListener extends BaseListener
|
||||
}
|
||||
|
||||
private void trySetPersonResigned(OrgUserStatusChangedEvent event) {
|
||||
EssOrg org = essOrgDao.findOrNull(event.getOuId());
|
||||
if (org == null) return;
|
||||
EssPerson person = essPersonDao.findOrNull(event.getOuId(), event.getPersonId());
|
||||
if (person == null)
|
||||
if (person == null) {
|
||||
essLogDao.log("personResigned", event.getPersonId(),
|
||||
"event", event, "isAuthorized", false);
|
||||
return;
|
||||
}
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(event.getOuId());
|
||||
if (superAdmin.getPersonId().equals(event.getPersonId())) {
|
||||
boolean isSuperAdmin = superAdmin.getPersonId().equals(event.getPersonId());
|
||||
essLogDao.log("personResigned", person.getPersonId(),
|
||||
"event", event, "isSuperAdmin", isSuperAdmin);
|
||||
if (isSuperAdmin) {
|
||||
log.info("ignore super admin resigned: {}", JSON.toJSONString(person));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -56,8 +56,7 @@ public class QueryService {
|
||||
private final EssSealPersonDao essSealPersonDao;
|
||||
private final EssSupport essSupport;
|
||||
|
||||
public List<GetOrgAuthStatesResponse>
|
||||
getEssUnitAuthStates(GetOrgAuthStatesRequest request) {
|
||||
public List<GetOrgAuthStatesResponse> getOrgAuthStates(GetOrgAuthStatesRequest request) {
|
||||
List<EssOrg> orgs = essOrgDao.getByOuIds(request.getOuIds());
|
||||
ArrayList<GetOrgAuthStatesResponse> responses = new ArrayList<>();
|
||||
for (Long ouId : request.getOuIds()) {
|
||||
@ -118,7 +117,7 @@ public class QueryService {
|
||||
EssOrgAndSealInfo orgAndSeal = new EssOrgAndSealInfo();
|
||||
essOrgAndSeals.add(orgAndSeal);
|
||||
orgAndSeal.setOrg(BeanMapper.copyBean(org, EssOrgInfo.class));
|
||||
orgAndSeal.getOrg().setOrgAuthorized(org.getIsAuthorized().isYes());
|
||||
orgAndSeal.getOrg().setOrgAuthorized(org.isAuthorized());
|
||||
List<EssSeal> seals = ouId2Seals.getOrDefault(org.getOuId(), emptyList());
|
||||
orgAndSeal.setSeals(BeanMapper.copyList(seals, EssSealInfo.class));
|
||||
for (EssSealInfo sealInfo : orgAndSeal.getSeals()) {
|
||||
@ -133,14 +132,12 @@ public class QueryService {
|
||||
sealPersonInfo.setSuperAdmin(org.getSuperAdminPersonId().equals(sealPerson.getPersonId()));
|
||||
sealPersonInfo.setSealAuthorized(sealPerson.getIsAuthorized().isYes());
|
||||
sealPersonInfo.setPersonAuthorized(essPerson.isAuthorized());
|
||||
PersonProfileDto personProfile = personProfiles
|
||||
.find(sealPerson.getPersonId()).orElse(null);
|
||||
sealPersonInfo.setPersonName(
|
||||
personProfile == null ? "" : personProfile.getRealName());
|
||||
PersonProfileDto authorizedByPersonProfile = personProfiles
|
||||
.find(sealPerson.getPersonId()).orElse(null);
|
||||
sealPersonInfo.setAuthorizedByPersonName(
|
||||
authorizedByPersonProfile == null ? "" : authorizedByPersonProfile.getRealName());
|
||||
sealPersonInfo.setAuthorizeTimeMs(sealPerson.getAuthorizeTime() == null
|
||||
? null : sealPerson.getAuthorizeTime().getTime());
|
||||
PersonProfileDto person = personProfiles.findOrNull(sealPerson.getPersonId());
|
||||
sealPersonInfo.setPersonName(person == null ? "" : person.getRealName());
|
||||
PersonProfileDto authorizedBy = personProfiles.findOrNull(sealPerson.getPersonId());
|
||||
sealPersonInfo.setAuthorizedByPersonName(authorizedBy == null ? "" : authorizedBy.getRealName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,28 +7,26 @@ import cn.axzo.nanopart.ess.api.domain.EssOrgAndSealInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.EssContractInfo;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AddSealPersonsRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.AssignWeixinAppUrlByOrgRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.DownloadSingedContractPdfRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetContractDetailByBizCodeRequest;
|
||||
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.GetSealsRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.GetSignUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.RemoveSealAuthorizationRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.RemoveSealPersonRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
|
||||
import cn.axzo.nanopart.ess.api.response.AssignWeixinAppUrlByOrgResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateConsoleLoginUrlResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateContractResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.CreateContractByFileResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.DownloadSingedContractPdfResponse;
|
||||
import cn.axzo.nanopart.ess.api.response.GetContractDetailByBizCodeResponse;
|
||||
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.api.response.GetSignUrlResponse;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssContract;
|
||||
import cn.axzo.nanopart.ess.server.ess.ContractManager;
|
||||
@ -57,7 +55,7 @@ class ApiController implements EssApi {
|
||||
|
||||
@Override
|
||||
public ApiResult<List<GetOrgAuthStatesResponse>> getOrgAuthStates(GetOrgAuthStatesRequest request) {
|
||||
return ApiResult.ok(queryService.getEssUnitAuthStates(request));
|
||||
return ApiResult.ok(queryService.getOrgAuthStates(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -109,14 +107,14 @@ class ApiController implements EssApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<CreateContractResponse> createContract(CreateContractRequest request) {
|
||||
return ApiResult.ok(contractManager.createContract(request));
|
||||
public ApiResult<CreateContractByFileResponse> createContractByFile(CreateContractByFileRequest request) {
|
||||
return ApiResult.ok(contractManager.createContractByFile(request));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<AssignWeixinAppUrlByOrgResponse> assignWeixinAppUrlByOrg(AssignWeixinAppUrlByOrgRequest request) {
|
||||
AssignWeixinAppUrlByOrgResponse response = new AssignWeixinAppUrlByOrgResponse();
|
||||
response.setUrl(essService.assignWeixinAppUrlByOrg(request));
|
||||
public ApiResult<GetSignUrlResponse> getContractSignUrl(GetSignUrlRequest request) {
|
||||
GetSignUrlResponse response = new GetSignUrlResponse();
|
||||
response.setUrl(essService.getContractSignUrl(request));
|
||||
return ApiResult.ok(response);
|
||||
}
|
||||
|
||||
@ -135,20 +133,11 @@ class ApiController implements EssApi {
|
||||
|
||||
@Override
|
||||
public ApiResult<GetContractDetailByContractIdResponse>
|
||||
getContractDetailByContractId(GetContractDetailByContractIdRequest request) {
|
||||
getContractByContractId(GetContractDetailByContractIdRequest request) {
|
||||
EssContract contract = essContractDao.getOrThrow(request.getEssContractId());
|
||||
GetContractDetailByContractIdResponse response = new GetContractDetailByContractIdResponse();
|
||||
response.setContract(BeanMapper.copyBean(contract, EssContractInfo.class));
|
||||
return ApiResult.ok(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ApiResult<GetContractDetailByBizCodeResponse>
|
||||
getContractDetailByBizCode(GetContractDetailByBizCodeRequest request) {
|
||||
EssContract contract = essContractDao.findByBizCode(request.getAppCode(), request.getBizCode()).orElse(null);
|
||||
GetContractDetailByBizCodeResponse response = new GetContractDetailByBizCodeResponse();
|
||||
response.setContract(BeanMapper.copyBean(contract, EssContractInfo.class));
|
||||
return ApiResult.ok(response);
|
||||
}
|
||||
|
||||
}
|
||||
@ -24,7 +24,6 @@ import cn.axzo.nanopart.ess.server.ess.domain.JsonObjectAsString;
|
||||
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.EssSupport;
|
||||
import cn.axzo.nanopart.ess.server.ess.support.OssService;
|
||||
import cn.axzo.nanopart.ess.server.utils.IdBuilder;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import lombok.AccessLevel;
|
||||
@ -56,7 +55,6 @@ class CallbackController implements EssCallbackApi, InitializingBean {
|
||||
|
||||
private final OrgManager orgManager;
|
||||
private final EssService essService;
|
||||
private final OssService ossService;
|
||||
private final ContractManager contractManager;
|
||||
private final EssLogDao essLogDao;
|
||||
private final EssContractDao essContractDao;
|
||||
@ -72,17 +70,18 @@ class CallbackController implements EssCallbackApi, InitializingBean {
|
||||
OrgAuthorizationFinish result = request.readMsgData(OrgAuthorizationFinish.class);
|
||||
PersonOpenId person = PersonOpenId.parse(result.getProxyOperatorOpenId());
|
||||
if (result.isOpenSuccess()) {
|
||||
orgManager.addAuthorizedOrgPerson(person.getOuId(), person.getPersonId());
|
||||
orgManager.addAuthorizedOrgPerson(person);
|
||||
orgManager.setOrgAuthorized(person.getOuId(), person.getPersonId());
|
||||
}
|
||||
return IdBuilder.builder()
|
||||
.append(person.getOuId())
|
||||
.append(person.getPersonId()).build();
|
||||
.append(person.getPersonId())
|
||||
.build();
|
||||
});
|
||||
// 员工加入子企业的时候发送此通知
|
||||
registerHandler(CallbackType.ORG_PERSON_JOIN, request -> {
|
||||
PersonOpenId person = PersonOpenId.parse(request.readMsgData(OrgPersonJoin.class).getProxyOperatorOpenId());
|
||||
orgManager.addAuthorizedOrgPerson(person.getOuId(), person.getPersonId());
|
||||
orgManager.addAuthorizedOrgPerson(person);
|
||||
// 一般情况下只会存在一条记录
|
||||
for (EssSealPerson sealPerson : essSealPersonDao.getByPersonId(person.getPersonId())) {
|
||||
AddSealAuthorizationRequest addSealAuthorizationRequest = new AddSealAuthorizationRequest();
|
||||
@ -97,7 +96,8 @@ class CallbackController implements EssCallbackApi, InitializingBean {
|
||||
}
|
||||
return IdBuilder.builder()
|
||||
.append(person.getOuId())
|
||||
.append(person.getPersonId()).build();
|
||||
.append(person.getPersonId())
|
||||
.build();
|
||||
});
|
||||
// 印章回调
|
||||
registerHandler(CallbackType.SEAL_OPERATE, request -> {
|
||||
@ -157,7 +157,7 @@ class CallbackController implements EssCallbackApi, InitializingBean {
|
||||
return detail;
|
||||
})
|
||||
.collect(toList());
|
||||
EssContract contract = essContractDao.find(changes.getFlowId()).orElse(null);
|
||||
EssContract contract = essContractDao.findOrNull(changes.getFlowId());
|
||||
if (contract == null && StringUtils.isNotBlank(changes.getCustomerData())) {
|
||||
JSONObject customData = JsonObjectAsString.parse(changes.getCustomerData()).asJsonObject();
|
||||
contract = essContractDao.getById(customData.getLong(ContractManager.CONTRACT_ID));
|
||||
@ -165,7 +165,8 @@ class CallbackController implements EssCallbackApi, InitializingBean {
|
||||
if (contract != null) {
|
||||
contractManager.updateContractState(contract, state, approveDetails);
|
||||
EssContract finalContract = contract;
|
||||
ossService.maybeDownloadToOss(contract, () -> essService.getContractPDFUrlFromEss(finalContract));
|
||||
essService.maybeUploadContractToOss(contract.getEssContractId(),
|
||||
() -> essService.getContractPDFUrlFromEss(finalContract));
|
||||
}
|
||||
return changes.getFlowId();
|
||||
});
|
||||
@ -184,10 +185,18 @@ class CallbackController implements EssCallbackApi, InitializingBean {
|
||||
try {
|
||||
CallbackType callbackType = CallbackType.parse(request.getMsgType()).orElse(null);
|
||||
CallbackHandler handler = callbackType == null ? null : handlers.get(callbackType);
|
||||
if (handler != null)
|
||||
subject = transactionTemplate.execute(unused -> handler.handle(request));
|
||||
else
|
||||
if (handler != null) {
|
||||
subject = transactionTemplate.execute(unused -> {
|
||||
try {
|
||||
return handler.handle(request);
|
||||
} catch (Exception e) {
|
||||
log.warn("callback failed", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
log.info("ignore callback: {}", request);
|
||||
}
|
||||
return ApiResult.ok("success");
|
||||
} finally {
|
||||
saveRequest(request, subject);
|
||||
|
||||
@ -29,16 +29,15 @@ public class PrivateController {
|
||||
private final EssClient essClient;
|
||||
private final EssOrgDao essOrgDao;
|
||||
|
||||
@SuppressWarnings("DataFlowIssue")
|
||||
@PostMapping("/private/ess/getOrgEmployees")
|
||||
public ApiResult<?> getOrgUsers(@RequestParam("ouId") Long ouId) {
|
||||
EssOrg org = essOrgDao.find(ouId).orElse(null);
|
||||
@PostMapping("/private/ess/getOrgPersons")
|
||||
public ApiResult<?> getOrgPersons(@RequestParam("ouId") Long ouId) {
|
||||
EssOrg org = essOrgDao.findOrNull(ouId);
|
||||
BizAssertions.assertNotNull(org, "电子签单位不存在");
|
||||
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(ouId);
|
||||
HashMap<String, Staff> staffs = new HashMap<>();
|
||||
long offset = 0L;
|
||||
while (true) {
|
||||
ChannelDescribeEmployeesResponse response = essClient.getEmployees(superAdmin, org, offset);
|
||||
ChannelDescribeEmployeesResponse response = essClient.getOrgPerson(superAdmin, org, offset);
|
||||
if (response.getEmployees() == null || response.getEmployees().length == 0)
|
||||
break;
|
||||
offset = response.getOffset() + 1;
|
||||
|
||||
@ -10,7 +10,7 @@ import lombok.RequiredArgsConstructor;
|
||||
*/
|
||||
@Getter
|
||||
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public class PersonOpenId {
|
||||
public class PersonOpenId implements OrgPerson {
|
||||
|
||||
private static final PersonOpenId NONE = create(0L, 0L);
|
||||
|
||||
|
||||
@ -0,0 +1,87 @@
|
||||
package cn.axzo.nanopart.ess.server.ess.support;
|
||||
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
import cn.axzo.nanopart.ess.api.domain.CreateContractInfo;
|
||||
import cn.axzo.nanopart.ess.api.domain.contract.Approver;
|
||||
import cn.axzo.nanopart.ess.api.enums.Constraint;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractState;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssOrgDao;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssContract;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssOrg;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
*/
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ContractSupport {
|
||||
|
||||
private final EssOrgDao essOrgDao;
|
||||
private final EssContractDao essContractDao;
|
||||
|
||||
public void validateCreateContract(CreateContractInfo contract) {
|
||||
checkCreateContractConstraint(contract);
|
||||
ensureOrgAuthorized(contract);
|
||||
}
|
||||
|
||||
private void checkCreateContractConstraint(CreateContractInfo contract) {
|
||||
if (contract.getConstraint() == Constraint.ONE_PERSON_PER_ORG) {
|
||||
HashSet<Long> ouIds = new HashSet<>();
|
||||
for (Approver approver : contract.getApprovers()) {
|
||||
if (approver.getSignPerson() == null)
|
||||
continue;
|
||||
BizAssertions.assertFalse(ouIds.contains(approver.getOuId()),
|
||||
"同一单位不能有多个审批人, constraint={}", Constraint.ONE_PERSON_PER_ORG);
|
||||
ouIds.add(approver.getOuId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureOrgAuthorized(CreateContractInfo contract) {
|
||||
BizAssertions.assertNotNull(contract, "合同信息不能为空");
|
||||
List<EssOrg> orgs = essOrgDao.getByOuIds(contract.getApproverOuIds());
|
||||
List<String> notAuthorizedOrgs = orgs.stream()
|
||||
.filter(org -> !org.isAuthorized())
|
||||
.map(EssOrg::getOuName)
|
||||
.collect(toList());
|
||||
BizAssertions.assertEmpty(notAuthorizedOrgs,
|
||||
"创建合同失败. 以下单位还未认证: {}", JSON.toJSONString(notAuthorizedOrgs));
|
||||
}
|
||||
|
||||
public EssContract saveContractByFile(CreateContractByFileRequest request) {
|
||||
try {
|
||||
EssContract contract = new EssContract();
|
||||
contract.setAppCode(request.getAppCode());
|
||||
contract.setBizCode(request.getBizCode());
|
||||
contract.setCreatorOuId(request.getCreator().getOuId());
|
||||
contract.setCreatorPersonId(request.getCreator().getPersonId());
|
||||
contract.setContractName(request.getByFile().getContractName());
|
||||
contract.setEssContractId("");
|
||||
contract.setEssFieldIds(Collections.emptyList());
|
||||
contract.setState(EssContractState.INIT);
|
||||
contract.setApprovers(request.getByFile().getApprovers());
|
||||
contract.getOrCreateAssignment().setConstraint(
|
||||
request.getContract().getConstraint());
|
||||
contract.setApproveDetails(Collections.emptyList());
|
||||
contract.setRecordExt(new EssContract.RecordExt());
|
||||
essContractDao.save(contract);
|
||||
return contract;
|
||||
} catch (DuplicateKeyException e) {
|
||||
throw new ServiceException("业务编码对应的合同已存在");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -6,31 +6,30 @@ import cn.axzo.basics.profiles.dto.request.QueryPersonProfileByIdOrPhoneDto;
|
||||
import cn.axzo.maokai.api.client.OrganizationalUnitApi;
|
||||
import cn.axzo.maokai.api.vo.request.OrganizationalUnitQuery;
|
||||
import cn.axzo.maokai.api.vo.response.OrganizationalUnitVO;
|
||||
import cn.axzo.nanopart.ess.api.domain.DynamicApproverProps;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssContractState;
|
||||
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
|
||||
import cn.axzo.nanopart.ess.api.enums.EssPersonState;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
|
||||
import cn.axzo.nanopart.ess.api.request.CreateContractRequest;
|
||||
import cn.axzo.nanopart.ess.api.utils.YesOrNo;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssContract;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssOrg;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssPerson;
|
||||
import cn.axzo.nanopart.ess.server.entity.domain.AssignedApprovers;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import cn.azxo.framework.common.model.CommonResponse;
|
||||
import com.tencentcloudapi.essbasic.v20210526.models.ApproverItem;
|
||||
import cn.hutool.core.thread.NamedThreadFactory;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.ThreadPoolExecutor.CallerRunsPolicy;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static cn.axzo.nanopart.ess.server.utils.BizAssertions.assertResponse;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
|
||||
/**
|
||||
@ -40,6 +39,12 @@ import static java.util.stream.Collectors.toList;
|
||||
@RequiredArgsConstructor
|
||||
public class EssSupport {
|
||||
|
||||
private final ExecutorService executor = new ThreadPoolExecutor(1, 5,
|
||||
0L, TimeUnit.MILLISECONDS,
|
||||
new ArrayBlockingQueue<>(1024),
|
||||
new NamedThreadFactory(EssSupport.class.getName(), false),
|
||||
new CallerRunsPolicy());
|
||||
|
||||
private final OrganizationalUnitApi organizationalUnitApi;
|
||||
private final UserProfileServiceApi userProfileServiceApi;
|
||||
|
||||
@ -55,16 +60,16 @@ public class EssSupport {
|
||||
return org;
|
||||
}
|
||||
|
||||
public EssPerson createPerson(Long ouId, Long personId) {
|
||||
PersonProfileDto personProfile = getPersonProfileOrThrow(personId);
|
||||
EssPerson person = new EssPerson();
|
||||
person.setOuId(ouId);
|
||||
person.setPersonId(personId);
|
||||
person.setPersonName(personProfile.getRealName());
|
||||
person.setState(EssPersonState.CREATED);
|
||||
person.setCreateAt(new Date());
|
||||
person.setUpdateAt(new Date());
|
||||
return person;
|
||||
public EssPerson createPerson(OrgPerson orgPerson) {
|
||||
PersonProfileDto personProfile = getPersonProfileOrThrow(orgPerson);
|
||||
EssPerson essPerson = new EssPerson();
|
||||
essPerson.setOuId(orgPerson.getOuId());
|
||||
essPerson.setPersonId(orgPerson.getPersonId());
|
||||
essPerson.setPersonName(personProfile.getRealName());
|
||||
essPerson.setState(EssPersonState.CREATED);
|
||||
essPerson.setCreateAt(new Date());
|
||||
essPerson.setUpdateAt(new Date());
|
||||
return essPerson;
|
||||
}
|
||||
|
||||
public OrganizationalUnitVO getOrgProfileOrThrow(Long ouId) {
|
||||
@ -82,9 +87,9 @@ public class EssSupport {
|
||||
return assertResponse(organizationalUnitApi.list(request));
|
||||
}
|
||||
|
||||
public PersonProfileDto getPersonProfileOrThrow(Long personId) {
|
||||
PersonProfileDto person = findPersonProfile(personId).orElse(null);
|
||||
BizAssertions.assertNotNull(person, "人员不存在: {}", personId);
|
||||
public PersonProfileDto getPersonProfileOrThrow(OrgPerson orgPerson) {
|
||||
PersonProfileDto person = findPersonProfile(orgPerson).orElse(null);
|
||||
BizAssertions.assertNotNull(person, "人员不存在: {}", orgPerson.getPersonId());
|
||||
return person;
|
||||
}
|
||||
|
||||
@ -95,8 +100,8 @@ public class EssSupport {
|
||||
return CollectionUtils.isEmpty(profiles) ? Optional.empty() : Optional.of(profiles.get(0));
|
||||
}
|
||||
|
||||
public Optional<PersonProfileDto> findPersonProfile(Long personId) {
|
||||
CommonResponse<PersonProfileDto> response = userProfileServiceApi.getPersonProfile(personId);
|
||||
public Optional<PersonProfileDto> findPersonProfile(OrgPerson orgPerson) {
|
||||
CommonResponse<PersonProfileDto> response = userProfileServiceApi.getPersonProfile(orgPerson.getPersonId());
|
||||
if (response.getCode() == 404)
|
||||
return Optional.empty();
|
||||
return Optional.ofNullable(assertResponse(response));
|
||||
@ -108,38 +113,8 @@ public class EssSupport {
|
||||
return assertResponse(userProfileServiceApi.getPersonProfiles(personIds));
|
||||
}
|
||||
|
||||
public EssContract createContract(CreateContractRequest request) {
|
||||
EssContract contract = new EssContract();
|
||||
contract.setAppCode(request.getAppCode());
|
||||
contract.setBizCode(request.getBizCode());
|
||||
contract.setCreatorOuId(request.getOperator().getOuId());
|
||||
contract.setCreatorPersonId(request.getOperator().getPersonId());
|
||||
contract.setContractName(request.getByFile().getContractName());
|
||||
contract.setEssContractId("");
|
||||
contract.setEssFieldIds(Collections.emptyList());
|
||||
contract.setState(EssContractState.INIT);
|
||||
contract.setIsDynamicApprover(YesOrNo.valueOf(
|
||||
request.getByFile().isDynamicApprover()));
|
||||
contract.setApprovers(request.getByFile().getApprovers());
|
||||
if (request.getByFile().isDynamicApprover()) {
|
||||
DynamicApproverProps props = request.getByFile().getDynamicApproverProps();
|
||||
if (props == null)
|
||||
props = DynamicApproverProps.defaultProps();
|
||||
AssignedApprovers assignedApprovers = new AssignedApprovers();
|
||||
assignedApprovers.setAssignType(props.getAssignType());
|
||||
contract.setAssignedApprovers(assignedApprovers);
|
||||
}
|
||||
contract.setApproveDetails(Collections.emptyList());
|
||||
contract.setRecordExt(new EssContract.RecordExt());
|
||||
return contract;
|
||||
}
|
||||
|
||||
public static List<String> collectRecipientIds(ApproverItem[] approvers) {
|
||||
if (approvers == null || approvers.length == 0)
|
||||
return Collections.emptyList();
|
||||
return Arrays.stream(approvers)
|
||||
.map(ApproverItem::getRecipientId)
|
||||
.collect(toList());
|
||||
public void asyncExec(Runnable task) {
|
||||
executor.execute(task);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,8 +1,5 @@
|
||||
package cn.axzo.nanopart.ess.server.ess.support;
|
||||
|
||||
import cn.axzo.basics.common.exception.ServiceException;
|
||||
import cn.axzo.nanopart.ess.server.dao.EssContractDao;
|
||||
import cn.axzo.nanopart.ess.server.entity.EssContract;
|
||||
import cn.axzo.nanopart.ess.server.utils.BizAssertions;
|
||||
import cn.axzo.oss.http.api.ServerFileServiceApi;
|
||||
import cn.axzo.oss.http.model.ApiSignUrlDownloadRequest;
|
||||
@ -12,7 +9,6 @@ import cn.axzo.oss.http.model.ApiSignUrlUploadResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
@ -25,9 +21,8 @@ import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static cn.axzo.nanopart.ess.server.utils.BizAssertions.fail;
|
||||
|
||||
/**
|
||||
* @author yanglin
|
||||
@ -37,21 +32,8 @@ import java.util.function.Supplier;
|
||||
@RequiredArgsConstructor
|
||||
public class OssService {
|
||||
|
||||
private final EssContractDao essContractDao;
|
||||
private final ServerFileServiceApi serverFileServiceApi;
|
||||
private final EssProps essProps;
|
||||
private final ExecutorService executor = Executors.newSingleThreadExecutor();
|
||||
|
||||
public void maybeDownloadToOss(EssContract contract, Supplier<String> essPdfUrl) {
|
||||
executor.execute(() -> {
|
||||
if (!contract.getState().isFinalState()
|
||||
|| StringUtils.isNotBlank(contract.getOssFileKey()))
|
||||
return;
|
||||
String fileName = String.format("%s.pdf", contract.getContractName());
|
||||
String fileKey = saveToOss(essPdfUrl.get(), fileName);
|
||||
essContractDao.setOssInfo(contract, fileKey);
|
||||
});
|
||||
}
|
||||
|
||||
public String getOssUrl(String fileKey) {
|
||||
ApiSignUrlDownloadRequest request = new ApiSignUrlDownloadRequest();
|
||||
@ -63,17 +45,6 @@ public class OssService {
|
||||
return CollectionUtils.isEmpty(responses) ? null : responses.get(0).getSignUrl();
|
||||
}
|
||||
|
||||
public String saveToOss(String contentUrl, String fileName) {
|
||||
try {
|
||||
ApiSignUrlUploadResponse ossResponse = prepareOss(fileName);
|
||||
streamUpload(ossResponse, urlDownload(contentUrl), fileName);
|
||||
return ossResponse.getFileKey();
|
||||
} catch (Exception e) {
|
||||
log.warn("下载合同并上传到OSS失败", e);
|
||||
throw new ServiceException("下载合同并上传到OSS失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
private ApiSignUrlUploadResponse prepareOss(String fileName) {
|
||||
ApiSignUrlUploadRequest ossRequest = new ApiSignUrlUploadRequest();
|
||||
ossRequest.setAppCode(essProps.getOssAppCode());
|
||||
@ -83,10 +54,22 @@ public class OssService {
|
||||
.assertResponse(serverFileServiceApi.signUrlFetchUpload(ossRequest));
|
||||
}
|
||||
|
||||
public String uploadToOss(String contentUrl, String fileName) {
|
||||
try {
|
||||
ApiSignUrlUploadResponse ossResponse = prepareOss(fileName);
|
||||
streamUpload(ossResponse, urlDownload(contentUrl), fileName);
|
||||
return ossResponse.getFileKey();
|
||||
} catch (Exception e) {
|
||||
log.warn("下载合同并上传到OSS失败", e);
|
||||
throw fail(e, "下载合同并上传到OSS失败");
|
||||
}
|
||||
}
|
||||
|
||||
private byte[] urlDownload(String url) throws IOException {
|
||||
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
|
||||
con.setRequestMethod("GET");
|
||||
con.setConnectTimeout(4 * 1000);
|
||||
con.setConnectTimeout(10 * 1000);
|
||||
con.setReadTimeout(10 * 1000);
|
||||
InputStream inStream = con.getInputStream();
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[2048];
|
||||
|
||||
@ -26,14 +26,15 @@ public class PersonProfiles {
|
||||
}
|
||||
|
||||
public PersonProfileDto getOrThrow(Long personId) {
|
||||
PersonProfileDto person = find(personId).orElse(null);
|
||||
PersonProfileDto person = findOrNull(personId);
|
||||
BizAssertions.assertNotNull(person, "找不到人员信息, personId={}", personId);
|
||||
return person;
|
||||
}
|
||||
|
||||
public Optional<PersonProfileDto> find(Long personId) {
|
||||
public PersonProfileDto findOrNull(Long personId) {
|
||||
return profiles.stream()
|
||||
.filter(p -> p.getId().equals(personId))
|
||||
.findFirst();
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@ -21,6 +21,21 @@ import java.util.Objects;
|
||||
@Slf4j
|
||||
public class BizAssertions {
|
||||
|
||||
public static ServiceException fail(String message, Object... args) {
|
||||
return new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
|
||||
}
|
||||
|
||||
public static ServiceException fail(Exception e, String message, Object... args) {
|
||||
return new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage(), e);
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言集合为空
|
||||
*/
|
||||
public static void assertEmpty(Collection<?> actual, String message, Object... args) {
|
||||
AssertUtil.isEmpty(actual, MessageFormatter.arrayFormat(message, args).getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言为NULL
|
||||
*/
|
||||
@ -42,13 +57,6 @@ public class BizAssertions {
|
||||
AssertUtil.notEmpty(actual, MessageFormatter.arrayFormat(message, args).getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言集合为空
|
||||
*/
|
||||
public static void assertEmpty(Collection<?> actual, String message, Object... args) {
|
||||
AssertUtil.isEmpty(actual, MessageFormatter.arrayFormat(message, args).getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 断言数组不为空
|
||||
*/
|
||||
@ -100,13 +108,21 @@ public class BizAssertions {
|
||||
}
|
||||
}
|
||||
|
||||
private static String messageOrTemplateMessage(String message, String template, Object... args) {
|
||||
if (message != null) {
|
||||
return message;
|
||||
}
|
||||
return MessageFormatter.arrayFormat(template, args).getMessage();
|
||||
}
|
||||
|
||||
public static <T> T assertResponse(CommonResponse<T> response) {
|
||||
return assertResponse(response, "error resp={}", JSON.toJSONString(response));
|
||||
}
|
||||
|
||||
public static <T> T assertResponse(CommonResponse<T> response, String message, Object... args) {
|
||||
if (response == null || response.getCode() != HttpStatus.HTTP_OK) {
|
||||
ServiceException e = new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
|
||||
ServiceException e = new ServiceException(messageOrTemplateMessage(
|
||||
response == null ? null : response.getMsg(), message, args));
|
||||
log.warn("remote call response with error", e);
|
||||
throw e;
|
||||
}
|
||||
@ -119,7 +135,7 @@ public class BizAssertions {
|
||||
|
||||
public static <T> T assertResponse(ApiResult<T> response, String message, Object... args) {
|
||||
if (!response.isSuccess()) {
|
||||
ServiceException e = new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
|
||||
ServiceException e = new ServiceException(messageOrTemplateMessage(response.getMsg(), message, args));
|
||||
log.warn("remote call response with error", e);
|
||||
throw e;
|
||||
}
|
||||
@ -132,29 +148,11 @@ public class BizAssertions {
|
||||
|
||||
public static <T> List<T> assertResponse(ApiListResult<T> response, String message, Object... args) {
|
||||
if (!response.isSuccess()) {
|
||||
ServiceException e = new ServiceException(MessageFormatter.arrayFormat(message, args).getMessage());
|
||||
ServiceException e = new ServiceException(messageOrTemplateMessage(response.getMsg(), message, args));
|
||||
log.warn("remote call response with error", e);
|
||||
throw e;
|
||||
}
|
||||
return response.getData();
|
||||
}
|
||||
|
||||
|
||||
public static <T> T assertResponse(cn.axzo.foundation.result.ApiResult<T> response) {
|
||||
return assertResponse(response, "error resp={}", JSON.toJSONString(response));
|
||||
}
|
||||
|
||||
public static <T> T assertResponse(cn.axzo.foundation.result.ApiResult<T> response, String message, Object... args) {
|
||||
if (!response.isSuccess()) {
|
||||
String finalMsg = MessageFormatter.arrayFormat(message, args).getMessage();
|
||||
if (StringUtils.isNotBlank(response.getMsg())) {
|
||||
finalMsg += ": " + response.getMsg();
|
||||
}
|
||||
ServiceException e = new ServiceException(finalMsg);
|
||||
log.warn("remote call response with error. response={}", JSON.toJSONString(response), e);
|
||||
throw e;
|
||||
}
|
||||
return response.getData();
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user