diff --git a/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/domain/DynamicApproverProps.java b/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/domain/DynamicApproverProps.java new file mode 100644 index 00000000..bdd7b1ba --- /dev/null +++ b/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/domain/DynamicApproverProps.java @@ -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; + +} \ No newline at end of file diff --git a/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/domain/contract/EssApproveDetail.java b/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/domain/contract/EssApproveDetail.java index 17b72732..5441fb79 100644 --- a/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/domain/contract/EssApproveDetail.java +++ b/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/domain/contract/EssApproveDetail.java @@ -21,6 +21,9 @@ public class EssApproveDetail { */ private Long personId; + /** + * 签署编号 + */ private String recipientId; /** diff --git a/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/enums/ApproverAssignType.java b/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/enums/ApproverAssignType.java index ea5f46b0..7bef4edd 100644 --- a/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/enums/ApproverAssignType.java +++ b/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/enums/ApproverAssignType.java @@ -4,5 +4,10 @@ package cn.axzo.nanopart.ess.api.enums; * @author yanglin */ public enum ApproverAssignType { - ORG_WEIXIN_APP + + // 一个子客一个用户盖章 + ONE_PERSON_PER_ORG, + // 不做限制 + NONE + } \ No newline at end of file diff --git a/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/request/CreateContractInfo.java b/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/request/CreateContractInfo.java index 9050cef5..7cd5a43a 100644 --- a/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/request/CreateContractInfo.java +++ b/ess/ess-api/src/main/java/cn/axzo/nanopart/ess/api/request/CreateContractInfo.java @@ -1,5 +1,6 @@ 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 com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Getter; @@ -32,6 +33,12 @@ public class CreateContractInfo { */ private boolean dynamicApprover; + /** + * 动态签署人属性 + */ + @Valid + private DynamicApproverProps dynamicApproverProps; + /** * 合同签署方 */ diff --git a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/entity/EssContract.java b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/entity/EssContract.java index a9a6a057..364c056e 100644 --- a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/entity/EssContract.java +++ b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/entity/EssContract.java @@ -15,6 +15,7 @@ import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler; import lombok.Getter; import lombok.Setter; +import javax.swing.table.DefaultTableCellRenderer; import java.util.List; /** @@ -100,6 +101,17 @@ public class EssContract extends BaseEntity { @TableField(typeHandler = FastjsonTypeHandler.class) 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() { return approvers.size(); } diff --git a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/entity/domain/AssignedApprovers.java b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/entity/domain/AssignedApprovers.java index c56782e6..29c954f4 100644 --- a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/entity/domain/AssignedApprovers.java +++ b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/entity/domain/AssignedApprovers.java @@ -13,6 +13,6 @@ public class AssignedApprovers { private ApproverAssignType assignType; - private SignByOrg signByOrg; + private SignByOrg signByOrg = new SignByOrg(); } \ No newline at end of file diff --git a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/ContractManager.java b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/ContractManager.java index f851d3cc..f3ffa11b 100644 --- a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/ContractManager.java +++ b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/ContractManager.java @@ -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.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; @@ -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.EssSeal; 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.SealPersons; 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); BizAssertions.assertNotNull(contract, "找不到合同信息, essContractId={}", request.getEssContractId()); //noinspection DataFlowIssue - BizAssertions.assertTrue(contract.getIsDynamicApprover().isYes(), "合同不支持动态签署"); - BizAssertions.assertEquals(ApproverAssignType.ORG_WEIXIN_APP, contract.getAssignType(), "签署方式不正确"); + BizAssertions.assertEquals(ApproverAssignType.ONE_PERSON_PER_ORG, contract.getAssignType(), "签署方式不正确"); String recipientId = contract.getAssignedApprovers() .getSignByOrg() .assign(contract.getApprovers(), request.getOuId(), request.getRecipientId()); @@ -196,7 +195,8 @@ public class ContractManager { } public EssPerson getContractCreatorOrThrow(EssContract contract) { - EssPerson creator = essPersonDao.findOrNull(contract.getCreatorOuId(), contract.getCreatorPersonId()); + EssPerson creator = essPersonDao.findOrNull( + contract.getCreatorOuId(), contract.getCreatorPersonId()); BizAssertions.assertNotNull(creator, "找不到合同发起人信息"); return creator; } diff --git a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/EssClient.java b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/EssClient.java index 75d6e3a9..eeeb670e 100644 --- a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/EssClient.java +++ b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/EssClient.java @@ -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.EssSealPerson; 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.support.EssProps; 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.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; @@ -240,7 +239,7 @@ public class EssClient implements InitializingBean { approverInfo.setMobile(personProfile.getPhone()); approverInfo.setOpenId(PersonOpenId.create(approver).toOpenId()); approverInfo.setOrganizationName(orgProfile.getName()); - approverInfo.setOrganizationOpenId(OuOpenId.ofPerson(approver).toOpenId()); + approverInfo.setOrganizationOpenId(OrgOpenId.ofPerson(approver).toOpenId()); } approverInfo.setApproverType(approver.getApproverType().name()); approverInfo.setNotifyType("NONE"); @@ -286,7 +285,7 @@ public class EssClient implements InitializingBean { approverInfo.setApproverMobile(personProfile.getPhone()); approverInfo.setOpenId(PersonOpenId.create(approver).toOpenId()); approverInfo.setOrganizationName(orgProfile.getName()); - approverInfo.setOrganizationOpenId(OuOpenId.ofPerson(approver).toOpenId()); + approverInfo.setOrganizationOpenId(OrgOpenId.ofPerson(approver).toOpenId()); ChannelCreateFlowApproversRequest request = new ChannelCreateFlowApproversRequest(); request.setAgent(agent(contractCreator)); request.setFlowId(essContractId); @@ -336,18 +335,18 @@ public class EssClient implements InitializingBean { return response.getSignUrl(); } - public CreateSignUrlsResponse getContractSignUrlWeixinApp( - String essContractId, EssPerson signPerson, String recipientId) { + public CreateSignUrlsResponse assignWeixinAppUrlByOrg( + String essContractId, EssPerson creator, + OrgPerson signPerson, String recipientId) { CreateSignUrlsRequest request = new CreateSignUrlsRequest(); - request.setAgent(agent(signPerson)); + request.setAgent(agent(creator)); request.setFlowIds(new String[]{essContractId}); request.setOpenId(PersonOpenId.create(signPerson).toOpenId()); - if (StringUtils.isNotBlank(recipientId)) { - request.setRecipientIds(new String[]{recipientId}); - request.setGenerateType("RECIPIENT"); - } + request.setOrganizationOpenId(OrgOpenId.ofPerson(signPerson).toOpenId()); + request.setRecipientIds(new String[]{recipientId}); + request.setGenerateType("RECIPIENT"); return exec(func() - .context("CreateSignUrls") + .context("CreateSignUrls:assignWeixinAppUrlByOrg") .subject(essContractId) .request(request) .command(() -> manage.CreateSignUrls(request))); @@ -393,7 +392,7 @@ public class EssClient implements InitializingBean { UserInfo userInfo = new UserInfo(); agent.setAppId(props.getAppId()); agent.setProxyAppId(""); - agent.setProxyOrganizationOpenId(OuOpenId.ofPerson(person).toOpenId()); + agent.setProxyOrganizationOpenId(OrgOpenId.ofPerson(person).toOpenId()); userInfo.setOpenId(PersonOpenId.create(person).toOpenId()); agent.setProxyOperator(userInfo); return agent; diff --git a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/EssService.java b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/EssService.java index 0f409146..836c3db4 100644 --- a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/EssService.java +++ b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/EssService.java @@ -1,5 +1,7 @@ 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.SignUrlType; import cn.axzo.nanopart.ess.api.request.AddSealAuthorizationRequest; @@ -26,7 +28,6 @@ import com.tencentcloudapi.essbasic.v20210526.models.SignUrlInfo; import lombok.RequiredArgsConstructor; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Service; -import org.springframework.transaction.support.TransactionTemplate; /** * @author yanglin @@ -44,7 +45,6 @@ public class EssService { private final EssPersonDao essPersonDao; private final EssProps essProps; private final OssService ossService; - private final TransactionTemplate transactionTemplate; public String createConsoleLoginUrl(CreateConsoleLoginUrlRequest request) { OrgAndPerson orgAndPerson = orgManager.createConsoleLoginUrl(request); @@ -105,11 +105,18 @@ public class EssService { public String assignWeixinAppUrlByOrg(AssignWeixinAppUrlByOrgRequest request) { EssPerson signPerson = essPersonDao.findOrNull(request); BizAssertions.assertNotNull(signPerson, "当前签署人员未加入单位, 无法签署"); - String recipientId = contractManager.assignRecipientIdByOrg(request); 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); - CreateSignUrlsResponse essResponse = essClient - .getContractSignUrlWeixinApp(request.getEssContractId(), creator, recipientId); + CreateSignUrlsResponse essResponse = essClient.assignWeixinAppUrlByOrg( + request.getEssContractId(), creator, request, recipientId); SignUrlInfo signUrlInfo = essResponse.getSignUrlInfos()[0]; return request.getUrlType() == SignUrlType.PC ? signUrlInfo.getSignQrcodeUrl() diff --git a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/PersonResignListener.java b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/PersonResignListener.java index 8d8d4cbc..f9f9cc26 100644 --- a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/PersonResignListener.java +++ b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/PersonResignListener.java @@ -47,8 +47,8 @@ public class PersonResignListener extends BaseListener } @Override - public void onEvent(Event messageEvent, EventConsumer.Context context) { - OrgUserStatusChangedEvent userEvent = messageEvent.normalizedData(OrgUserStatusChangedEvent.class); + public void onEvent(Event event, EventConsumer.Context context) { + OrgUserStatusChangedEvent userEvent = event.normalizedData(OrgUserStatusChangedEvent.class); log.info("receive user event: {}", JSON.toJSONString(userEvent)); if (userEvent.getStatusCode() == 6) trySetPersonResigned(userEvent); @@ -56,10 +56,15 @@ public class PersonResignListener extends BaseListener log.info("ignore user event: {}", JSON.toJSONString(userEvent)); } - private void trySetPersonResigned(OrgUserStatusChangedEvent userEvent) { - EssPerson person = essPersonDao.findOrNull(userEvent.getOuId(), userEvent.getPersonId()); - if (person == null) return; - EssPerson superAdmin = orgManager.getSuperAdminOrThrow(userEvent.getOuId()); + private void trySetPersonResigned(OrgUserStatusChangedEvent event) { + EssPerson person = essPersonDao.findOrNull(event.getOuId(), event.getPersonId()); + if (person == null) + 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)); orgManager.setOrgPersonResign(person); log.info("set person resigned: {}", JSON.toJSONString(person)); diff --git a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/domain/OuOpenId.java b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/domain/OrgOpenId.java similarity index 65% rename from ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/domain/OuOpenId.java rename to ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/domain/OrgOpenId.java index 8d935499..e1d04947 100644 --- a/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/domain/OuOpenId.java +++ b/ess/ess-server/src/main/java/cn/axzo/nanopart/ess/server/ess/domain/OrgOpenId.java @@ -10,20 +10,20 @@ import lombok.RequiredArgsConstructor; */ @Getter @RequiredArgsConstructor(access = AccessLevel.PRIVATE) -public class OuOpenId { +public class OrgOpenId { private final Long ouId; - public static OuOpenId ofPerson(OrgPerson person) { + public static OrgOpenId ofPerson(OrgPerson person) { return create(person.getOuId()); } - public static OuOpenId create(Long ouId) { - return new OuOpenId(ouId); + public static OrgOpenId create(Long ouId) { + return new OrgOpenId(ouId); } - public static OuOpenId parse(String openId) { - return new OuOpenId(Long.parseLong(openId)); + public static OrgOpenId parse(String openId) { + return new OrgOpenId(Long.parseLong(openId)); } public String toOpenId() {