REQ-3581: 动态获取签署链接

This commit is contained in:
yanglin 2025-03-04 13:32:56 +08:00
parent bf7314a0ca
commit 401705544c
14 changed files with 191 additions and 86 deletions

View File

@ -1,11 +1,20 @@
package cn.axzo.nanopart.ess.api; package cn.axzo.nanopart.ess.api;
import java.util.List;
import javax.validation.Valid;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import cn.axzo.framework.domain.web.result.ApiResult; import cn.axzo.framework.domain.web.result.ApiResult;
import cn.axzo.nanopart.ess.api.domain.EssOrgAndSealInfo; import cn.axzo.nanopart.ess.api.domain.EssOrgAndSealInfo;
import cn.axzo.nanopart.ess.api.domain.EssSealPersonInfo; import cn.axzo.nanopart.ess.api.domain.EssSealPersonInfo;
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest; import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
import cn.axzo.nanopart.ess.api.request.AddSealPersonRequest; import cn.axzo.nanopart.ess.api.request.AddSealPersonRequest;
import cn.axzo.nanopart.ess.api.request.AssignSignUrlRequest;
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest; import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest; import cn.axzo.nanopart.ess.api.request.CreateContractByFileRequest;
import cn.axzo.nanopart.ess.api.request.DownloadSingedContractPdfRequest; import cn.axzo.nanopart.ess.api.request.DownloadSingedContractPdfRequest;
@ -15,11 +24,11 @@ import cn.axzo.nanopart.ess.api.request.GetOrgAuthStatesRequest;
import cn.axzo.nanopart.ess.api.request.GetPersonAuthStateRequest; import cn.axzo.nanopart.ess.api.request.GetPersonAuthStateRequest;
import cn.axzo.nanopart.ess.api.request.GetSealPersonRequest; import cn.axzo.nanopart.ess.api.request.GetSealPersonRequest;
import cn.axzo.nanopart.ess.api.request.GetSealsRequest; 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.RemoveSealAuthorizationRequest;
import cn.axzo.nanopart.ess.api.request.RemoveSealPersonRequest; import cn.axzo.nanopart.ess.api.request.RemoveSealPersonRequest;
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest; import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
import cn.axzo.nanopart.ess.api.request.SaveContractSnapshotRequest; import cn.axzo.nanopart.ess.api.request.SaveContractSnapshotRequest;
import cn.axzo.nanopart.ess.api.response.AssignSignUrlResponse;
import cn.axzo.nanopart.ess.api.response.CreateConsoleLoginUrlResponse; import cn.axzo.nanopart.ess.api.response.CreateConsoleLoginUrlResponse;
import cn.axzo.nanopart.ess.api.response.CreateContractByFileResponse; import cn.axzo.nanopart.ess.api.response.CreateContractByFileResponse;
import cn.axzo.nanopart.ess.api.response.DownloadSingedContractPdfResponse; import cn.axzo.nanopart.ess.api.response.DownloadSingedContractPdfResponse;
@ -27,13 +36,6 @@ import cn.axzo.nanopart.ess.api.response.GetContractDetailByContractIdResponse;
import cn.axzo.nanopart.ess.api.response.GetEmbedWebUrlResponse; import cn.axzo.nanopart.ess.api.response.GetEmbedWebUrlResponse;
import cn.axzo.nanopart.ess.api.response.GetOrgAuthStatesResponse; import cn.axzo.nanopart.ess.api.response.GetOrgAuthStatesResponse;
import cn.axzo.nanopart.ess.api.response.GetPersonAuthStateResponse; 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;
import javax.validation.Valid;
import java.util.List;
/** /**
* @author yanglin * @author yanglin
@ -110,10 +112,10 @@ public interface EssApi {
@RequestBody @Valid CreateContractByFileRequest request); @RequestBody @Valid CreateContractByFileRequest request);
/** /**
* 获取签署链接, 有效期为5分钟 * 获取动态签署链接, 有效期为5分钟
*/ */
@PostMapping("api/ess/getContractSignUrl") @PostMapping("api/ess/assignSignUrl")
ApiResult<GetSignUrlResponse> getContractSignUrl(@RequestBody @Valid GetSignUrlRequest request); ApiResult<AssignSignUrlResponse> assignSignUrl(@RequestBody @Valid AssignSignUrlRequest request);
/** /**
* 获取合同PDF文件地址. 下载链接有效期为5分钟 * 获取合同PDF文件地址. 下载链接有效期为5分钟

View File

@ -16,6 +16,10 @@ import javax.validation.constraints.NotNull;
@Getter @Getter
public class OrgPersonInfo implements OrgPerson { public class OrgPersonInfo implements OrgPerson {
public static OrgPersonInfo create(OrgPerson person) {
return create(person.getOuId(), person.getPersonId());
}
public static OrgPersonInfo create(Long ouId, Long personId) { public static OrgPersonInfo create(Long ouId, Long personId) {
OrgPersonInfo orgPersonInfo = new OrgPersonInfo(); OrgPersonInfo orgPersonInfo = new OrgPersonInfo();
orgPersonInfo.setOuId(ouId); orgPersonInfo.setOuId(ouId);

View File

@ -21,6 +21,6 @@ public class SignOption {
/** /**
* 是否可以转发. false-可以转发 true-不可以转发 * 是否可以转发. false-可以转发 true-不可以转发
*/ */
private boolean noTransfer = true; private boolean noTransfer = false;
} }

View File

@ -1,21 +1,22 @@
package cn.axzo.nanopart.ess.api.request; package cn.axzo.nanopart.ess.api.request;
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint;
import com.alibaba.fastjson.JSON;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull; import javax.validation.constraints.NotNull;
import com.alibaba.fastjson.JSON;
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint;
import lombok.Getter;
import lombok.Setter;
/** /**
* @author yanglin * @author yanglin
*/ */
@Setter @Setter
@Getter @Getter
public class GetSignUrlRequest implements OrgPerson { public class AssignSignUrlRequest implements OrgPerson {
/** /**
* 合同id * 合同id
@ -43,11 +44,8 @@ public class GetSignUrlRequest implements OrgPerson {
/** /**
* 签署方编号, 可以使用该编号指定动态签署方的信息, 该编号在创建合同的时候会返回 * 签署方编号, 可以使用该编号指定动态签署方的信息, 该编号在创建合同的时候会返回
* <p/>
* 如果在创建合同的时候存在任意没有指定具体签署人(Approver#signPersion)的情况下, 该字段必传
* <p/>
* 如果在创建合同的时候已经指定了所有的具体签署人(Approver#signPersion), 该字段可以不传
*/ */
@NotBlank(message = "recipientId不能为空")
private String recipientId; private String recipientId;
@Override @Override

View File

@ -10,7 +10,7 @@ import lombok.Setter;
*/ */
@Setter @Setter
@Getter @Getter
public class GetSignUrlResponse { public class AssignSignUrlResponse {
/** /**
* 有效期为5分钟. * 有效期为5分钟.

View File

@ -18,7 +18,7 @@
<dependency> <dependency>
<groupId>com.tencentcloudapi</groupId> <groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId> <artifactId>tencentcloud-sdk-java</artifactId>
<version>3.1.1209</version> <version>3.1.1210</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>cn.axzo.framework</groupId> <groupId>cn.axzo.framework</groupId>

View File

@ -1,20 +1,22 @@
package cn.axzo.nanopart.ess.server.dao; package cn.axzo.nanopart.ess.server.dao;
import java.util.List;
import java.util.Optional;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.axzo.nanopart.ess.api.domain.contract.Approver; import cn.axzo.nanopart.ess.api.domain.contract.Approver;
import cn.axzo.nanopart.ess.api.domain.contract.EssApproveDetail; import cn.axzo.nanopart.ess.api.domain.contract.EssApproveDetail;
import cn.axzo.nanopart.ess.api.enums.EssContractState; import cn.axzo.nanopart.ess.api.enums.EssContractState;
import cn.axzo.nanopart.ess.server.entity.EssContract; import cn.axzo.nanopart.ess.server.entity.EssContract;
import cn.axzo.nanopart.ess.server.mapper.EssContractMapper; import cn.axzo.nanopart.ess.server.mapper.EssContractMapper;
import cn.axzo.nanopart.ess.server.utils.BizAssertions; import cn.axzo.nanopart.ess.server.utils.BizAssertions;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
/** /**
* @author yanglin * @author yanglin
@ -39,8 +41,10 @@ public class EssContractDao extends ServiceImpl<EssContractMapper, EssContract>
return find(essContractId, false).orElse(null); return find(essContractId, false).orElse(null);
} }
public EssContract findForUpdateOrNull(String essContractId) { public EssContract getForUpdateOrThrow(String essContractId) {
return find(essContractId, true).orElse(null); EssContract contract = find(essContractId, true).orElse(null);
BizAssertions.assertNotNull(contract, "找不到合同信息, 合同id={}", essContractId);
return contract;
} }
private Optional<EssContract> find(String essContractId, boolean forUpdate) { private Optional<EssContract> find(String essContractId, boolean forUpdate) {
@ -77,6 +81,15 @@ public class EssContractDao extends ServiceImpl<EssContractMapper, EssContract>
.update(); .update();
} }
public void updateAssigment(EssContract contract) {
if (contract.getAssignment() == null)
return;
lambdaUpdate() //
.eq(EssContract::getId, contract.getId()) //
.set(EssContract::getAssignment, JSON.toJSONString(contract.getAssignment())) //
.update();
}
public void updateExt(EssContract contract) { public void updateExt(EssContract contract) {
if (contract.getRecordExt() == null) if (contract.getRecordExt() == null)
return; return;

View File

@ -14,4 +14,6 @@ public class Assignment {
private Constraint constraint; private Constraint constraint;
} private SignPerOrgs signPerOrgs = new SignPerOrgs();
}

View File

@ -0,0 +1,15 @@
package cn.axzo.nanopart.ess.server.entity.domain;
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter @Getter
public class SignPerOrg implements OrgPerson {
private Long ouId;
private Long personId;
private String recipientId;
}

View File

@ -0,0 +1,39 @@
package cn.axzo.nanopart.ess.server.entity.domain;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import cn.axzo.nanopart.ess.api.domain.OrgPerson;
import lombok.Getter;
import lombok.Setter;
/**
* @author yanglin
*/
@Setter
@Getter
public class SignPerOrgs {
private List<SignPerOrg> signPerOrg = new ArrayList<>();
public Optional<SignPerOrg> find(Long ouId) {
return signPerOrg.stream() //
.filter(orgPersonInfo -> orgPersonInfo.getOuId().equals(ouId)) //
.findFirst();
}
public void remove(Long ouId) {
signPerOrg.removeIf(org -> org.getOuId().equals(ouId));
}
public void add(OrgPerson person, String recipientId) {
SignPerOrg orgPersonInfo = new SignPerOrg();
orgPersonInfo.setOuId(person.getOuId());
orgPersonInfo.setPersonId(person.getPersonId());
orgPersonInfo.setRecipientId(recipientId);
signPerOrg.add(orgPersonInfo);
}
}

View File

@ -87,7 +87,7 @@ public class ContractManager {
public void revokeContract(RevokeContractRequest request) { public void revokeContract(RevokeContractRequest request) {
essLogDao.logRequest("revokeContract", request.getEssContractId(), request); essLogDao.logRequest("revokeContract", request.getEssContractId(), request);
// lock when updating state // lock when updating state
EssContract contract = essContractDao.findForUpdateOrNull(request.getEssContractId()); EssContract contract = essContractDao.getForUpdateOrThrow(request.getEssContractId());
BizAssertions.assertFalse(contract.isFinalState(), "合同已是终态 {}, 无法撤销", contract.getState().description()); BizAssertions.assertFalse(contract.isFinalState(), "合同已是终态 {}, 无法撤销", contract.getState().description());
EssPerson superAdmin = getContractSuperAdmin(contract); EssPerson superAdmin = getContractSuperAdmin(contract);
essClient.revokeContract(superAdmin, contract.getEssContractId(), request.getReason()); essClient.revokeContract(superAdmin, contract.getEssContractId(), request.getReason());
@ -97,8 +97,7 @@ public class ContractManager {
@BizTransactional @BizTransactional
public void updateContractState(EssContract contract, EssContractState state, List<EssApproveDetail> approveDetails, public void updateContractState(EssContract contract, EssContractState state, List<EssApproveDetail> approveDetails,
String essMessage) { String essMessage) {
EssContract reload = essContractDao.findForUpdateOrNull(contract.getEssContractId()); EssContract reload = essContractDao.getForUpdateOrThrow(contract.getEssContractId());
BizAssertions.assertNotNull(reload, "合同不存在: {}", contract.getEssContractId());
if (reload.isFinalState()) { if (reload.isFinalState()) {
log.warn("合同[{}]已是最终状态[{}], 无法更新状态至{}", reload.getEssContractId(), reload.getState(), state.description()); log.warn("合同[{}]已是最终状态[{}], 无法更新状态至{}", reload.getEssContractId(), reload.getState(), state.description());
} }

View File

@ -17,6 +17,7 @@ import java.util.regex.Pattern;
import javax.annotation.Resource; import javax.annotation.Resource;
import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsResponse;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@ -38,6 +39,7 @@ import com.tencentcloudapi.essbasic.v20210526.models.ApproverOption;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCancelFlowRequest; import com.tencentcloudapi.essbasic.v20210526.models.ChannelCancelFlowRequest;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateEmbedWebUrlRequest; import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateEmbedWebUrlRequest;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateEmbedWebUrlResponse; 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.ChannelCreateFlowByFilesRequest;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowByFilesResponse; import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateFlowByFilesResponse;
import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateOrganizationBatchSignUrlRequest; import com.tencentcloudapi.essbasic.v20210526.models.ChannelCreateOrganizationBatchSignUrlRequest;
@ -49,11 +51,13 @@ import com.tencentcloudapi.essbasic.v20210526.models.ChannelDescribeEmployeesRes
import com.tencentcloudapi.essbasic.v20210526.models.ComponentLimit; import com.tencentcloudapi.essbasic.v20210526.models.ComponentLimit;
import com.tencentcloudapi.essbasic.v20210526.models.CreateConsoleLoginUrlRequest; import com.tencentcloudapi.essbasic.v20210526.models.CreateConsoleLoginUrlRequest;
import com.tencentcloudapi.essbasic.v20210526.models.CreateConsoleLoginUrlResponse; import com.tencentcloudapi.essbasic.v20210526.models.CreateConsoleLoginUrlResponse;
import com.tencentcloudapi.essbasic.v20210526.models.CreateFlowForwardsRequest;
import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsRequest; import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsRequest;
import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsResponse;
import com.tencentcloudapi.essbasic.v20210526.models.DescribeResourceUrlsByFlowsRequest; import com.tencentcloudapi.essbasic.v20210526.models.DescribeResourceUrlsByFlowsRequest;
import com.tencentcloudapi.essbasic.v20210526.models.DescribeResourceUrlsByFlowsResponse; 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.FlowApproverInfo;
import com.tencentcloudapi.essbasic.v20210526.models.FlowForwardInfo;
import com.tencentcloudapi.essbasic.v20210526.models.ProxyOrganizationOperator; import com.tencentcloudapi.essbasic.v20210526.models.ProxyOrganizationOperator;
import com.tencentcloudapi.essbasic.v20210526.models.SyncProxyOrganizationOperatorsRequest; import com.tencentcloudapi.essbasic.v20210526.models.SyncProxyOrganizationOperatorsRequest;
import com.tencentcloudapi.essbasic.v20210526.models.UploadFile; import com.tencentcloudapi.essbasic.v20210526.models.UploadFile;
@ -299,21 +303,43 @@ public class EssClient implements InitializingBean {
return response.getFlowResourceUrlInfos()[0].getResourceUrlInfos()[0].getUrl(); return response.getFlowResourceUrlInfos()[0].getResourceUrlInfos()[0].getUrl();
} }
public String getContractSignUrlPC(String essContractId, EssPerson signPerson) { void createFlowApprovers(EssPerson superAdmin, String essContractId, String recipientId, EssPerson signPerson) {
FillApproverInfo approver = new FillApproverInfo();
approver.setRecipientId(recipientId);
approver.setOpenId(PersonOpenId.create(signPerson).toOpenId());
approver.setOrganizationOpenId(OrgOpenId.ofPerson(signPerson).toOpenId());
ChannelCreateFlowApproversRequest request = new ChannelCreateFlowApproversRequest();
request.setAgent(agent(superAdmin));
request.setApprovers(new FillApproverInfo[] { approver });
request.setFlowId(essContractId);
request.setFillApproverType(1L);
exec(func() //
.context("ChannelCreateFlowApprovers") //
.subject(idbuilder() //
.append(essContractId) //
.append(signPerson.getPersonId()) //
.build()) //
.request(request) //
.command(() -> manage.ChannelCreateFlowApprovers(request)));
}
public String createPcSignUrl(EssPerson superAdmin, String essContractId, EssPerson signPerson) {
ChannelCreateOrganizationBatchSignUrlRequest request = new ChannelCreateOrganizationBatchSignUrlRequest(); ChannelCreateOrganizationBatchSignUrlRequest request = new ChannelCreateOrganizationBatchSignUrlRequest();
request.setAgent(agent(signPerson)); request.setAgent(agent(superAdmin));
request.setFlowIds(new String[] { essContractId }); request.setFlowIds(new String[] { essContractId });
request.setOpenId(PersonOpenId.create(signPerson).toOpenId()); request.setOpenId(PersonOpenId.create(signPerson).toOpenId());
ChannelCreateOrganizationBatchSignUrlResponse response = exec(func() // ChannelCreateOrganizationBatchSignUrlResponse response = exec(func() //
.context("ChannelCreateOrganizationBatchSignUrl") // .context("ChannelCreateOrganizationBatchSignUrl").subject(idbuilder() //
.subject(essContractId) // .append(essContractId) //
.append(signPerson.getPersonId()) //
.build()) //
.request(request) // .request(request) //
.command(() -> manage.ChannelCreateOrganizationBatchSignUrl(request))); .command(() -> manage.ChannelCreateOrganizationBatchSignUrl(request)));
return response.getSignUrl(); return response.getSignUrl();
} }
public CreateSignUrlsResponse getWeixinAppSignUrl(String essContractId, EssPerson superAdmin, OrgPerson signPerson, public String createSignUrls(EssPerson superAdmin, String essContractId, String recipientId,
String recipientId) { OrgPerson signPerson) {
CreateSignUrlsRequest request = new CreateSignUrlsRequest(); CreateSignUrlsRequest request = new CreateSignUrlsRequest();
request.setAgent(agent(superAdmin)); request.setAgent(agent(superAdmin));
request.setFlowIds(new String[] { essContractId }); request.setFlowIds(new String[] { essContractId });
@ -323,7 +349,7 @@ public class EssClient implements InitializingBean {
request.setRecipientIds(new String[] { recipientId }); request.setRecipientIds(new String[] { recipientId });
request.setGenerateType("RECIPIENT"); request.setGenerateType("RECIPIENT");
} }
return exec(func() // CreateSignUrlsResponse response = exec(func() //
.context("CreateSignUrls") // .context("CreateSignUrls") //
.subject(idbuilder() // .subject(idbuilder() //
.append(essContractId) // .append(essContractId) //
@ -331,6 +357,25 @@ public class EssClient implements InitializingBean {
.build()) // .build()) //
.request(request) // .request(request) //
.command(() -> manage.CreateSignUrls(request))); .command(() -> manage.CreateSignUrls(request)));
return response.getSignUrlInfos()[0].getSignUrl();
}
public void forward(EssPerson superAdmin, String essContractId, String recipientId, EssPerson signPerson) {
CreateFlowForwardsRequest request = new CreateFlowForwardsRequest();
request.setAgent(agent(superAdmin));
request.setTargetOpenId(PersonOpenId.create(signPerson).toOpenId());
FlowForwardInfo forward = new FlowForwardInfo();
forward.setFlowId(essContractId);
forward.setRecipientId(recipientId);
request.setFlowForwardInfos(new FlowForwardInfo[] { forward });
exec(func() //
.context("CreateFlowForwards") //
.subject(idbuilder() //
.append(essContractId) //
.append(signPerson.getPersonId()) //
.build()) //
.request(request) //
.command(() -> manage.CreateFlowForwards(request)));
} }
public void setEmployeeResigned(EssPerson superAdmin, EssPerson person) { public void setEmployeeResigned(EssPerson superAdmin, EssPerson person) {

View File

@ -3,25 +3,15 @@ package cn.axzo.nanopart.ess.server.ess;
import static cn.axzo.nanopart.ess.server.utils.IdBuilder.idbuilder; import static cn.axzo.nanopart.ess.server.utils.IdBuilder.idbuilder;
import java.util.function.Function;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import com.tencentcloudapi.essbasic.v20210526.models.CreateSignUrlsResponse;
import com.tencentcloudapi.essbasic.v20210526.models.SignUrlInfo;
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.Constraint; import cn.axzo.nanopart.ess.api.enums.Constraint;
import cn.axzo.nanopart.ess.api.enums.EssContractApproveState;
import cn.axzo.nanopart.ess.api.enums.EssEmbedType.EssSubject; import cn.axzo.nanopart.ess.api.enums.EssEmbedType.EssSubject;
import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint; import cn.axzo.nanopart.ess.api.enums.SignUrlEndpoint;
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest; import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
import cn.axzo.nanopart.ess.api.request.AssignSignUrlRequest;
import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest; import cn.axzo.nanopart.ess.api.request.CreateConsoleLoginUrlRequest;
import cn.axzo.nanopart.ess.api.request.GetEmbedWebUrlRequest; 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.RemoveSealAuthorizationRequest;
import cn.axzo.nanopart.ess.api.request.SaveContractSnapshotRequest; import cn.axzo.nanopart.ess.api.request.SaveContractSnapshotRequest;
import cn.axzo.nanopart.ess.api.request.SealAndPersonRequest; import cn.axzo.nanopart.ess.api.request.SealAndPersonRequest;
@ -132,38 +122,36 @@ public class EssService {
return new SealAndPerson(seal, sealPerson); return new SealAndPerson(seal, sealPerson);
} }
public String getContractSignUrl(GetSignUrlRequest request) { @BizTransactional
public String assignSignUrl(AssignSignUrlRequest request) {
String subject = idbuilder() // String subject = idbuilder() //
.append(request.getEssContractId()) // .append(request.getEssContractId()) //
.append(request.getOuId()) // .append(request.getOuId()) //
.append(request.getPersonId()) // .append(request.getPersonId()) //
.build(); .build();
essLogDao.logRequest("getContractSignUrl", subject, request); essLogDao.logRequest("assignSignUrl", subject, request);
EssPerson signPerson = essPersonDao.findOrNull(request); EssPerson signPerson = essPersonDao.findOrNull(request);
BizAssertions.assertNotNull(signPerson, "当前签署人员未加入单位, 无法签署"); BizAssertions.assertNotNull(signPerson, "当前签署人员未加入单位, 无法签署");
EssContract contract = essContractDao.getOrThrow(request.getEssContractId()); EssContract contract = essContractDao.getForUpdateOrThrow(request.getEssContractId());
BizAssertions.assertFalse(contract.isFinalState(), "合同已是最终状态 {}, 无法签署", contract.getState()); BizAssertions.assertFalse(contract.isFinalState(), "合同已是最终状态 {}, 无法签署", contract.getState());
if (contract.getConstraint() == Constraint.ONE_PERSON_PER_ORG) if (contract.getConstraint() == Constraint.ONE_PERSON_PER_ORG)
BizAssertions.assertFalse(contract.isOrgSigned(request.getOuId()), "该单位已签署, 无法再次签署"); BizAssertions.assertFalse(contract.isOrgSigned(request.getOuId()), "该单位已签署, 无法再次签署");
Function<String, String> signUrlFun = recipientId -> { contract.getAssignment().getSignPerOrgs().find(request.getOuId()).ifPresent(org -> {
EssPerson superAdmin = contractManager.getContractSuperAdmin(contract); BizAssertions.assertEquals(org.getRecipientId(), request.getRecipientId(), "单位的签署编号不能变化");
CreateSignUrlsResponse essResponse = essClient.getWeixinAppSignUrl(request.getEssContractId(), superAdmin, if (!org.getPersonId().equals(request.getPersonId())) {
request, recipientId); EssPerson signSuperAdmin = orgManager.getSuperAdminOrThrow(signPerson.getOuId());
SignUrlInfo signUrlInfo = essResponse.getSignUrlInfos()[0]; essClient.forward(signSuperAdmin, contract.getEssContractId(), request.getRecipientId(), signPerson);
return request.getEndpoint() == SignUrlEndpoint.PC ? signUrlInfo.getSignQrcodeUrl() }
: signUrlInfo.getSignUrl(); });
}; contract.getAssignment().getSignPerOrgs().remove(request.getOuId());
if (contract.isSignPersonsPreset()) contract.getAssignment().getSignPerOrgs().add(signPerson, request.getRecipientId());
return signUrlFun.apply(null); essContractDao.updateAssigment(contract);
BizAssertions.assertFalse(StringUtils.isBlank(request.getRecipientId()), "存在动态签署人的情况下, recipientId不能为空"); EssPerson superAdmin = contractManager.getContractSuperAdmin(contract);
EssApproveDetail approveDetail = contract.getApproveDetailOrThrow(request.getRecipientId()); if (request.getEndpoint() != SignUrlEndpoint.PC)
BizAssertions.assertNotEquals(EssContractApproveState.ACCEPT, approveDetail.getState(), "该签署位已签署, 无法再次签署"); return essClient.createSignUrls(superAdmin, contract.getEssContractId(), request.getRecipientId(),
Approver approver = contract.getApproverOrThrow(request.getRecipientId()); signPerson);
if (approver.getSignPerson() != null) { essClient.createFlowApprovers(superAdmin, contract.getEssContractId(), request.getRecipientId(), signPerson);
BizAssertions.assertTrue(OrgPerson.equals(approver.getSignPerson(), request), "签署人员不匹配"); return essClient.createPcSignUrl(superAdmin, contract.getEssContractId(), signPerson);
return signUrlFun.apply(null);
}
return signUrlFun.apply(request.getRecipientId());
} }
public String getContractPDFUrl(String essContractId) { public String getContractPDFUrl(String essContractId) {

View File

@ -22,7 +22,7 @@ import cn.axzo.nanopart.ess.api.request.GetOrgAuthStatesRequest;
import cn.axzo.nanopart.ess.api.request.GetPersonAuthStateRequest; import cn.axzo.nanopart.ess.api.request.GetPersonAuthStateRequest;
import cn.axzo.nanopart.ess.api.request.GetSealPersonRequest; import cn.axzo.nanopart.ess.api.request.GetSealPersonRequest;
import cn.axzo.nanopart.ess.api.request.GetSealsRequest; import cn.axzo.nanopart.ess.api.request.GetSealsRequest;
import cn.axzo.nanopart.ess.api.request.GetSignUrlRequest; import cn.axzo.nanopart.ess.api.request.AssignSignUrlRequest;
import cn.axzo.nanopart.ess.api.request.RemoveSealAuthorizationRequest; import cn.axzo.nanopart.ess.api.request.RemoveSealAuthorizationRequest;
import cn.axzo.nanopart.ess.api.request.RemoveSealPersonRequest; import cn.axzo.nanopart.ess.api.request.RemoveSealPersonRequest;
import cn.axzo.nanopart.ess.api.request.RevokeContractRequest; import cn.axzo.nanopart.ess.api.request.RevokeContractRequest;
@ -34,7 +34,7 @@ import cn.axzo.nanopart.ess.api.response.GetContractDetailByContractIdResponse;
import cn.axzo.nanopart.ess.api.response.GetEmbedWebUrlResponse; import cn.axzo.nanopart.ess.api.response.GetEmbedWebUrlResponse;
import cn.axzo.nanopart.ess.api.response.GetOrgAuthStatesResponse; import cn.axzo.nanopart.ess.api.response.GetOrgAuthStatesResponse;
import cn.axzo.nanopart.ess.api.response.GetPersonAuthStateResponse; import cn.axzo.nanopart.ess.api.response.GetPersonAuthStateResponse;
import cn.axzo.nanopart.ess.api.response.GetSignUrlResponse; import cn.axzo.nanopart.ess.api.response.AssignSignUrlResponse;
import cn.axzo.nanopart.ess.server.dao.EssContractDao; import cn.axzo.nanopart.ess.server.dao.EssContractDao;
import cn.axzo.nanopart.ess.server.entity.EssContract; import cn.axzo.nanopart.ess.server.entity.EssContract;
import cn.axzo.nanopart.ess.server.ess.ContractManager; import cn.axzo.nanopart.ess.server.ess.ContractManager;
@ -133,10 +133,10 @@ class ApiController implements EssApi {
} }
@Override @Override
public ApiResult<GetSignUrlResponse> getContractSignUrl(GetSignUrlRequest request) { public ApiResult<AssignSignUrlResponse> assignSignUrl(AssignSignUrlRequest request) {
log.info("getContractSignUrl request={}", request); log.info("assignSignUrl request={}", request);
GetSignUrlResponse response = new GetSignUrlResponse(); AssignSignUrlResponse response = new AssignSignUrlResponse();
response.setUrl(essService.getContractSignUrl(request)); response.setUrl(essService.assignSignUrl(request));
return ApiResult.ok(response); return ApiResult.ok(response);
} }