REQ-3581: 备份

This commit is contained in:
yanglin 2025-02-18 15:21:41 +08:00
parent 83ea8da3c5
commit 880d65bb4d
11 changed files with 101 additions and 36 deletions

View File

@ -0,0 +1,27 @@
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;
}

View File

@ -21,6 +21,9 @@ public class EssApproveDetail {
*/ */
private Long personId; private Long personId;
/**
* 签署编号
*/
private String recipientId; private String recipientId;
/** /**

View File

@ -4,5 +4,10 @@ package cn.axzo.nanopart.ess.api.enums;
* @author yanglin * @author yanglin
*/ */
public enum ApproverAssignType { public enum ApproverAssignType {
ORG_WEIXIN_APP
// 一个子客一个用户盖章
ONE_PERSON_PER_ORG,
// 不做限制
NONE
} }

View File

@ -1,5 +1,6 @@
package cn.axzo.nanopart.ess.api.request; package cn.axzo.nanopart.ess.api.request;
import cn.axzo.nanopart.ess.api.domain.DynamicApproverProps;
import cn.axzo.nanopart.ess.api.domain.contract.Approver; import cn.axzo.nanopart.ess.api.domain.contract.Approver;
import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter; import lombok.Getter;
@ -32,6 +33,12 @@ public class CreateContractInfo {
*/ */
private boolean dynamicApprover; private boolean dynamicApprover;
/**
* 动态签署人属性
*/
@Valid
private DynamicApproverProps dynamicApproverProps;
/** /**
* 合同签署方 * 合同签署方
*/ */

View File

@ -15,6 +15,7 @@ import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import javax.swing.table.DefaultTableCellRenderer;
import java.util.List; import java.util.List;
/** /**
@ -100,6 +101,17 @@ public class EssContract extends BaseEntity<EssContract> {
@TableField(typeHandler = FastjsonTypeHandler.class) @TableField(typeHandler = FastjsonTypeHandler.class)
private RecordExt recordExt; private RecordExt recordExt;
public boolean isDynamicApprover() {
return isDynamicApprover.isYes();
}
public boolean isOrgSigned(Long ouId) {
if (approveDetails == null)
return false;
return approveDetails.stream()
.anyMatch(detail -> detail.getOuId().equals(ouId));
}
public int preciseApproverSize() { public int preciseApproverSize() {
return approvers.size(); return approvers.size();
} }

View File

@ -13,6 +13,6 @@ public class AssignedApprovers {
private ApproverAssignType assignType; private ApproverAssignType assignType;
private SignByOrg signByOrg; private SignByOrg signByOrg = new SignByOrg();
} }

View File

@ -4,6 +4,7 @@ import cn.axzo.basics.common.exception.ServiceException;
import cn.axzo.nanopart.ess.api.domain.OrgPerson; 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.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.ApproverAssignType;
import cn.axzo.nanopart.ess.api.enums.EssContractState; import cn.axzo.nanopart.ess.api.enums.EssContractState;
import cn.axzo.nanopart.ess.api.enums.EssSealType; import cn.axzo.nanopart.ess.api.enums.EssSealType;
import cn.axzo.nanopart.ess.api.request.AssignWeixinAppUrlByOrgRequest; import cn.axzo.nanopart.ess.api.request.AssignWeixinAppUrlByOrgRequest;
@ -21,7 +22,6 @@ import cn.axzo.nanopart.ess.server.entity.EssOrg;
import cn.axzo.nanopart.ess.server.entity.EssPerson; import cn.axzo.nanopart.ess.server.entity.EssPerson;
import cn.axzo.nanopart.ess.server.entity.EssSeal; import cn.axzo.nanopart.ess.server.entity.EssSeal;
import cn.axzo.nanopart.ess.server.entity.EssSealPerson; import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
import cn.axzo.nanopart.ess.api.enums.ApproverAssignType;
import cn.axzo.nanopart.ess.server.ess.domain.JsonObjectAsString; 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.domain.SealPersons;
import cn.axzo.nanopart.ess.server.ess.support.EssSupport; import cn.axzo.nanopart.ess.server.ess.support.EssSupport;
@ -164,8 +164,7 @@ public class ContractManager {
EssContract contract = essContractDao.find(request.getEssContractId(), true).orElse(null); EssContract contract = essContractDao.find(request.getEssContractId(), true).orElse(null);
BizAssertions.assertNotNull(contract, "找不到合同信息, essContractId={}", request.getEssContractId()); BizAssertions.assertNotNull(contract, "找不到合同信息, essContractId={}", request.getEssContractId());
//noinspection DataFlowIssue //noinspection DataFlowIssue
BizAssertions.assertTrue(contract.getIsDynamicApprover().isYes(), "合同不支持动态签署"); BizAssertions.assertEquals(ApproverAssignType.ONE_PERSON_PER_ORG, contract.getAssignType(), "签署方式不正确");
BizAssertions.assertEquals(ApproverAssignType.ORG_WEIXIN_APP, contract.getAssignType(), "签署方式不正确");
String recipientId = contract.getAssignedApprovers() String recipientId = contract.getAssignedApprovers()
.getSignByOrg() .getSignByOrg()
.assign(contract.getApprovers(), request.getOuId(), request.getRecipientId()); .assign(contract.getApprovers(), request.getOuId(), request.getRecipientId());
@ -196,7 +195,8 @@ public class ContractManager {
} }
public EssPerson getContractCreatorOrThrow(EssContract contract) { public EssPerson getContractCreatorOrThrow(EssContract contract) {
EssPerson creator = essPersonDao.findOrNull(contract.getCreatorOuId(), contract.getCreatorPersonId()); EssPerson creator = essPersonDao.findOrNull(
contract.getCreatorOuId(), contract.getCreatorPersonId());
BizAssertions.assertNotNull(creator, "找不到合同发起人信息"); BizAssertions.assertNotNull(creator, "找不到合同发起人信息");
return creator; return creator;
} }

View File

@ -16,7 +16,7 @@ import cn.axzo.nanopart.ess.server.entity.EssPerson;
import cn.axzo.nanopart.ess.server.entity.EssSeal; import cn.axzo.nanopart.ess.server.entity.EssSeal;
import cn.axzo.nanopart.ess.server.entity.EssSealPerson; import cn.axzo.nanopart.ess.server.entity.EssSealPerson;
import cn.axzo.nanopart.ess.server.ess.EssClient.Func.FuncBuilder; import cn.axzo.nanopart.ess.server.ess.EssClient.Func.FuncBuilder;
import cn.axzo.nanopart.ess.server.ess.domain.OuOpenId; import cn.axzo.nanopart.ess.server.ess.domain.OrgOpenId;
import cn.axzo.nanopart.ess.server.ess.domain.PersonOpenId; import cn.axzo.nanopart.ess.server.ess.domain.PersonOpenId;
import cn.axzo.nanopart.ess.server.ess.support.EssProps; 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.EssSupport;
@ -62,7 +62,6 @@ import com.tencentcloudapi.essbasic.v20210526.models.UserInfo;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -240,7 +239,7 @@ public class EssClient implements InitializingBean {
approverInfo.setMobile(personProfile.getPhone()); approverInfo.setMobile(personProfile.getPhone());
approverInfo.setOpenId(PersonOpenId.create(approver).toOpenId()); approverInfo.setOpenId(PersonOpenId.create(approver).toOpenId());
approverInfo.setOrganizationName(orgProfile.getName()); approverInfo.setOrganizationName(orgProfile.getName());
approverInfo.setOrganizationOpenId(OuOpenId.ofPerson(approver).toOpenId()); approverInfo.setOrganizationOpenId(OrgOpenId.ofPerson(approver).toOpenId());
} }
approverInfo.setApproverType(approver.getApproverType().name()); approverInfo.setApproverType(approver.getApproverType().name());
approverInfo.setNotifyType("NONE"); approverInfo.setNotifyType("NONE");
@ -286,7 +285,7 @@ public class EssClient implements InitializingBean {
approverInfo.setApproverMobile(personProfile.getPhone()); approverInfo.setApproverMobile(personProfile.getPhone());
approverInfo.setOpenId(PersonOpenId.create(approver).toOpenId()); approverInfo.setOpenId(PersonOpenId.create(approver).toOpenId());
approverInfo.setOrganizationName(orgProfile.getName()); approverInfo.setOrganizationName(orgProfile.getName());
approverInfo.setOrganizationOpenId(OuOpenId.ofPerson(approver).toOpenId()); approverInfo.setOrganizationOpenId(OrgOpenId.ofPerson(approver).toOpenId());
ChannelCreateFlowApproversRequest request = new ChannelCreateFlowApproversRequest(); ChannelCreateFlowApproversRequest request = new ChannelCreateFlowApproversRequest();
request.setAgent(agent(contractCreator)); request.setAgent(agent(contractCreator));
request.setFlowId(essContractId); request.setFlowId(essContractId);
@ -336,18 +335,18 @@ public class EssClient implements InitializingBean {
return response.getSignUrl(); return response.getSignUrl();
} }
public CreateSignUrlsResponse getContractSignUrlWeixinApp( public CreateSignUrlsResponse assignWeixinAppUrlByOrg(
String essContractId, EssPerson signPerson, String recipientId) { String essContractId, EssPerson creator,
OrgPerson signPerson, String recipientId) {
CreateSignUrlsRequest request = new CreateSignUrlsRequest(); CreateSignUrlsRequest request = new CreateSignUrlsRequest();
request.setAgent(agent(signPerson)); request.setAgent(agent(creator));
request.setFlowIds(new String[]{essContractId}); request.setFlowIds(new String[]{essContractId});
request.setOpenId(PersonOpenId.create(signPerson).toOpenId()); request.setOpenId(PersonOpenId.create(signPerson).toOpenId());
if (StringUtils.isNotBlank(recipientId)) { request.setOrganizationOpenId(OrgOpenId.ofPerson(signPerson).toOpenId());
request.setRecipientIds(new String[]{recipientId}); request.setRecipientIds(new String[]{recipientId});
request.setGenerateType("RECIPIENT"); request.setGenerateType("RECIPIENT");
}
return exec(func() return exec(func()
.context("CreateSignUrls") .context("CreateSignUrls:assignWeixinAppUrlByOrg")
.subject(essContractId) .subject(essContractId)
.request(request) .request(request)
.command(() -> manage.CreateSignUrls(request))); .command(() -> manage.CreateSignUrls(request)));
@ -393,7 +392,7 @@ public class EssClient implements InitializingBean {
UserInfo userInfo = new UserInfo(); UserInfo userInfo = new UserInfo();
agent.setAppId(props.getAppId()); agent.setAppId(props.getAppId());
agent.setProxyAppId(""); agent.setProxyAppId("");
agent.setProxyOrganizationOpenId(OuOpenId.ofPerson(person).toOpenId()); agent.setProxyOrganizationOpenId(OrgOpenId.ofPerson(person).toOpenId());
userInfo.setOpenId(PersonOpenId.create(person).toOpenId()); userInfo.setOpenId(PersonOpenId.create(person).toOpenId());
agent.setProxyOperator(userInfo); agent.setProxyOperator(userInfo);
return agent; return agent;

View File

@ -1,5 +1,7 @@
package cn.axzo.nanopart.ess.server.ess; 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.enums.EssEmbedType.EssContext; import cn.axzo.nanopart.ess.api.enums.EssEmbedType.EssContext;
import cn.axzo.nanopart.ess.api.enums.SignUrlType; import cn.axzo.nanopart.ess.api.enums.SignUrlType;
import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest; import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest;
@ -26,7 +28,6 @@ import com.tencentcloudapi.essbasic.v20210526.models.SignUrlInfo;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;
/** /**
* @author yanglin * @author yanglin
@ -44,7 +45,6 @@ public class EssService {
private final EssPersonDao essPersonDao; private final EssPersonDao essPersonDao;
private final EssProps essProps; private final EssProps essProps;
private final OssService ossService; private final OssService ossService;
private final TransactionTemplate transactionTemplate;
public String createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) { public String createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) {
OrgAndPerson orgAndPerson = orgManager.createConsoleLoginUrl(request); OrgAndPerson orgAndPerson = orgManager.createConsoleLoginUrl(request);
@ -105,11 +105,18 @@ public class EssService {
public String assignWeixinAppUrlByOrg(AssignWeixinAppUrlByOrgRequest request) { public String assignWeixinAppUrlByOrg(AssignWeixinAppUrlByOrgRequest request) {
EssPerson signPerson = essPersonDao.findOrNull(request); EssPerson signPerson = essPersonDao.findOrNull(request);
BizAssertions.assertNotNull(signPerson, "当前签署人员未加入单位, 无法签署"); BizAssertions.assertNotNull(signPerson, "当前签署人员未加入单位, 无法签署");
String recipientId = contractManager.assignRecipientIdByOrg(request);
EssContract contract = essContractDao.getOrThrow(request.getEssContractId()); EssContract contract = essContractDao.getOrThrow(request.getEssContractId());
BizAssertions.assertTrue(contract.isDynamicApprover(), "合同不支持动态签署");
String recipientId;
if (contract.getAssignedApprovers().getAssignType() == ApproverAssignType.ONE_PERSON_PER_ORG) {
BizAssertions.assertFalse(contract.isOrgSigned(request.getOuId()), "该单位已签署, 无法再次签署");
recipientId = contractManager.assignRecipientIdByOrg(request);
} else {
throw new ServiceException(String.format("暂不支持的动态签署类型: %s", contract.getAssignedApprovers().getAssignType()));
}
EssPerson creator = contractManager.getContractCreatorOrThrow(contract); EssPerson creator = contractManager.getContractCreatorOrThrow(contract);
CreateSignUrlsResponse essResponse = essClient CreateSignUrlsResponse essResponse = essClient.assignWeixinAppUrlByOrg(
.getContractSignUrlWeixinApp(request.getEssContractId(), creator, recipientId); request.getEssContractId(), creator, request, recipientId);
SignUrlInfo signUrlInfo = essResponse.getSignUrlInfos()[0]; SignUrlInfo signUrlInfo = essResponse.getSignUrlInfos()[0];
return request.getUrlType() == SignUrlType.PC return request.getUrlType() == SignUrlType.PC
? signUrlInfo.getSignQrcodeUrl() ? signUrlInfo.getSignQrcodeUrl()

View File

@ -47,8 +47,8 @@ public class PersonResignListener extends BaseListener
} }
@Override @Override
public void onEvent(Event messageEvent, EventConsumer.Context context) { public void onEvent(Event event, EventConsumer.Context context) {
OrgUserStatusChangedEvent userEvent = messageEvent.normalizedData(OrgUserStatusChangedEvent.class); OrgUserStatusChangedEvent userEvent = event.normalizedData(OrgUserStatusChangedEvent.class);
log.info("receive user event: {}", JSON.toJSONString(userEvent)); log.info("receive user event: {}", JSON.toJSONString(userEvent));
if (userEvent.getStatusCode() == 6) if (userEvent.getStatusCode() == 6)
trySetPersonResigned(userEvent); trySetPersonResigned(userEvent);
@ -56,10 +56,15 @@ public class PersonResignListener extends BaseListener
log.info("ignore user event: {}", JSON.toJSONString(userEvent)); log.info("ignore user event: {}", JSON.toJSONString(userEvent));
} }
private void trySetPersonResigned(OrgUserStatusChangedEvent userEvent) { private void trySetPersonResigned(OrgUserStatusChangedEvent event) {
EssPerson person = essPersonDao.findOrNull(userEvent.getOuId(), userEvent.getPersonId()); EssPerson person = essPersonDao.findOrNull(event.getOuId(), event.getPersonId());
if (person == null) return; if (person == null)
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(userEvent.getOuId()); return;
EssPerson superAdmin = orgManager.getSuperAdminOrThrow(event.getOuId());
if (superAdmin.getPersonId().equals(event.getPersonId())) {
log.info("ignore super admin resigned: {}", JSON.toJSONString(person));
return;
}
essClient.setEmployeeResigned(superAdmin, Collections.singletonList(person)); essClient.setEmployeeResigned(superAdmin, Collections.singletonList(person));
orgManager.setOrgPersonResign(person); orgManager.setOrgPersonResign(person);
log.info("set person resigned: {}", JSON.toJSONString(person)); log.info("set person resigned: {}", JSON.toJSONString(person));

View File

@ -10,20 +10,20 @@ import lombok.RequiredArgsConstructor;
*/ */
@Getter @Getter
@RequiredArgsConstructor(access = AccessLevel.PRIVATE) @RequiredArgsConstructor(access = AccessLevel.PRIVATE)
public class OuOpenId { public class OrgOpenId {
private final Long ouId; private final Long ouId;
public static OuOpenId ofPerson(OrgPerson person) { public static OrgOpenId ofPerson(OrgPerson person) {
return create(person.getOuId()); return create(person.getOuId());
} }
public static OuOpenId create(Long ouId) { public static OrgOpenId create(Long ouId) {
return new OuOpenId(ouId); return new OrgOpenId(ouId);
} }
public static OuOpenId parse(String openId) { public static OrgOpenId parse(String openId) {
return new OuOpenId(Long.parseLong(openId)); return new OrgOpenId(Long.parseLong(openId));
} }
public String toOpenId() { public String toOpenId() {