diff --git a/backend/crm/src/main/java/cn/cordys/common/constants/FormKey.java b/backend/crm/src/main/java/cn/cordys/common/constants/FormKey.java index 830efeb1bb..ba96ee6e15 100644 --- a/backend/crm/src/main/java/cn/cordys/common/constants/FormKey.java +++ b/backend/crm/src/main/java/cn/cordys/common/constants/FormKey.java @@ -92,6 +92,6 @@ public static FormKey ofKey(String key) { } public boolean hasSnapshot() { - return Strings.CI.equalsAny(this.key, CONTRACT.getKey(), INVOICE.getKey(), QUOTATION.getKey()); + return Strings.CI.equalsAny(this.key, CONTRACT.getKey(), INVOICE.getKey(), QUOTATION.getKey(), ORDER.getKey()); } } diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalFlowService.java b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalFlowService.java index b2afa8c6bd..a629559347 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalFlowService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalFlowService.java @@ -1359,16 +1359,12 @@ public List resolveApprovers(String userId, String orgId, ApproverTypeEnum // 获取当前用户的组织用户信息 OrganizationUser currentUser = getOrganizationUser(userId, orgId); - if (currentUser == null) { - return List.of(); - } - return switch (approverType) { case MEMBER -> resolveMemberApprovers(orgId, approverList); case ROLE -> resolveRoleApprovers(orgId, approverList); case SUPERIOR -> resolveSuperiorApprovers(orgId, currentUser, approverList); case MULTIPLE_SUPERIOR -> resolveMultipleSuperiorApprovers(orgId, currentUser, approverList); - case DEPT_HEAD -> resolveDeptHeadApprovers(orgId, currentUser.getDepartmentId(), approverList); + case DEPT_HEAD -> resolveDeptHeadApprovers(orgId, currentUser, approverList); case MULTIPLE_DEPT_HEAD -> resolveMultipleDeptHeadApprovers(orgId, currentUser, approverList); }; } @@ -1410,6 +1406,9 @@ private List resolveRoleApprovers(String orgId, List roleIds) { * 解析指定上级审批人 */ private List resolveSuperiorApprovers(String orgId, OrganizationUser currentUser, List approverList) { + if (currentUser == null) { + return List.of(); + } // 值是单选 Integer approvalLevel = getValidLevel(approverList); @@ -1439,6 +1438,9 @@ private List resolveSuperiorApprovers(String orgId, OrganizationUser curre * 解析多级上级审批人 */ private List resolveMultipleSuperiorApprovers(String orgId, OrganizationUser currentUser, List approverList) { + if (currentUser == null) { + return List.of(); + } // 值是单选 Integer approvalLevel = getValidLevel(approverList); @@ -1483,7 +1485,11 @@ private Integer getValidLevel(List approverList) { /** * 解析部门负责人审批人 */ - private List resolveDeptHeadApprovers(String orgId, String departmentId, List approverList) { + private List resolveDeptHeadApprovers(String orgId, OrganizationUser currentUser, List approverList) { + if (currentUser == null) { + return List.of(); + } + String departmentId = currentUser.getDepartmentId(); if (StringUtils.isBlank(departmentId)) { return List.of(); } @@ -1523,6 +1529,9 @@ private String getDeptCommander(String orgId, String departmentId) { * 解析多级部门负责人审批人 */ private List resolveMultipleDeptHeadApprovers(String orgId, OrganizationUser currentUser, List approverList) { + if (currentUser == null) { + return List.of(); + } String departmentId = currentUser.getDepartmentId(); if (StringUtils.isBlank(departmentId)) { return List.of(); @@ -1586,6 +1595,18 @@ public List getCurrentNodeApproverList(String currentNodeId, String userId return resolveApprovers(userId, currentOrgId, ApproverTypeEnum.valueOf(nodeApprover.getApproverType()), JSON.parseArray(nodeApprover.getApproverList(), String.class)); } + /** + * 获取当前实例节点审批人 + * @param approverType 审批类型 + * @param approverList 审批人集合 + * @param userId 用户ID + * @param currentOrgId 当前组织ID + * @return 审批人ID集合 + */ + public List getCurrentNodeApproverList(String approverType, List approverList, String userId, String currentOrgId) { + return resolveApprovers(userId, currentOrgId, ApproverTypeEnum.valueOf(approverType), approverList); + } + /** * 获取当前实例节点抄送人 * @param currentNodeId 当前节点ID @@ -1598,6 +1619,18 @@ public List getCurrentNodeCcList(String currentNodeId, String userId, Stri return resolveApprovers(userId, currentOrgId, ApproverTypeEnum.valueOf(nodeApprover.getCcType()), JSON.parseArray(nodeApprover.getCcList(), String.class)); } + /** + * 获取当前实例节点抄送人 + * @param ccType 抄送类型 + * @param ccList 抄送人集合 + * @param userId 用户ID + * @param currentOrgId 当前组织ID + * @return 抄送人ID集合 + */ + public List getCurrentNodeCcList(String ccType, List ccList, String userId, String currentOrgId) { + return resolveApprovers(userId, currentOrgId, ApproverTypeEnum.valueOf(ccType), ccList); + } + /** * 获取当前资源审批实例第一个节点 * @param instance 审批实例 @@ -1643,8 +1676,8 @@ private ApprovalNodeResponse getNextNodeWithExceptionHandler(ApprovalInstance in ApprovalNodeApproverResponse nextApproverNode = (ApprovalNodeApproverResponse) nextNode; if (ApprovalTypeEnum.valueOf(nextApproverNode.getApprovalType()) == ApprovalTypeEnum.AUTO_PASS) { // 自动通过, 插入审批记录, 获取下一个节点 - saveAutoRecord(instance.getId(), nodeId, ApprovalStatus.APPROVED, null); - return getNextNodeWithExceptionHandler(instance, nodeId, fieldValues, currentOrgId); + saveAutoRecord(instance.getId(), nextApproverNode.getId(), ApprovalStatus.APPROVED, null); + return getNextNodeWithExceptionHandler(instance, nextApproverNode.getId(), fieldValues, currentOrgId); } if (ApprovalTypeEnum.valueOf(nextApproverNode.getApprovalType()) == ApprovalTypeEnum.AUTO_REJECT) { // 自动驳回, 插入审批记录 @@ -1654,8 +1687,8 @@ private ApprovalNodeResponse getNextNodeWithExceptionHandler(ApprovalInstance in return exNode; } // 人工审批, 异常处理 - List nextApprovers = getCurrentNodeApproverList(nextApproverNode.getId(), instance.getSubmitterId(), currentOrgId); - List nextCcList = getCurrentNodeCcList(nextApproverNode.getId(), instance.getSubmitterId(), currentOrgId); + List nextApprovers = getCurrentNodeApproverList(nextApproverNode.getApproverType(), nextApproverNode.getApproverList(), instance.getSubmitterId(), currentOrgId); + List nextCcList = getCurrentNodeCcList(nextApproverNode.getCcType(), nextApproverNode.getCcList(), instance.getSubmitterId(), currentOrgId); nextApproverNode.setApproverList(nextApprovers.stream().map(User::getId).collect(Collectors.toList())); nextApproverNode.setCcList(nextCcList.stream().map(User::getId).collect(Collectors.toList())); // 审批人为空 @@ -1664,8 +1697,8 @@ private ApprovalNodeResponse getNextNodeWithExceptionHandler(ApprovalInstance in switch (emptyAction) { case AUTO_PASS -> { // 自动通过, 插入审批记录, 获取下一个节点 - saveAutoRecord(instance.getId(), nodeId, ApprovalStatus.APPROVED, "审批人为空,自动通过"); - return getNextNodeWithExceptionHandler(instance, nodeId, fieldValues, currentOrgId); + saveAutoRecord(instance.getId(), nextApproverNode.getId(), ApprovalStatus.APPROVED, "审批人为空,自动通过"); + return getNextNodeWithExceptionHandler(instance, nextApproverNode.getId(), fieldValues, currentOrgId); } case ASSIGN_SPECIFIC -> { //指定人员处理: 返回人员列表 diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalInstanceService.java b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalInstanceService.java index 5d685603f1..eaa1968231 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalInstanceService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalInstanceService.java @@ -1,8 +1,10 @@ package cn.cordys.crm.approval.service; import cn.cordys.common.constants.FormKey; +import cn.cordys.common.exception.GenericException; import cn.cordys.common.util.BeanUtils; import cn.cordys.common.util.CommonBeanFactory; +import cn.cordys.common.util.Translator; import cn.cordys.crm.approval.constants.ApprovalAction; import cn.cordys.crm.approval.constants.ApprovalAddSignType; import cn.cordys.crm.approval.constants.ApprovalStatus; @@ -83,6 +85,9 @@ public ApprovalInstance getLatestInstance(String resourceId) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(ApprovalInstance::getResourceId, resourceId); List list = approvalInstanceMapper.selectListByLambda(wrapper); + if (CollectionUtils.isEmpty(list)) { + throw new GenericException(Translator.get("no.approval.instance")); + } return CollectionUtils.isEmpty(list) ? null : list.stream().sorted(Comparator.comparing(ApprovalInstance::getSubmitTime)).toList().getLast(); } diff --git a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalResourceService.java b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalResourceService.java index 0fca8d8894..55481a4b19 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalResourceService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/approval/service/ApprovalResourceService.java @@ -193,7 +193,8 @@ private void updateSnapshotApprovalStatus(FormKey formKey, String resourceId, St Map snapshotServiceMap = Map.of( FormKey.INVOICE, "contractInvoiceService", FormKey.QUOTATION, "opportunityQuotationService", - FormKey.CONTRACT, "customerContactService" + FormKey.CONTRACT, "contractService", + FormKey.ORDER, "orderService" ); String serviceBeanName = snapshotServiceMap.get(formKey); diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractInvoiceService.java b/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractInvoiceService.java index 17cde84398..c218d98428 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractInvoiceService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractInvoiceService.java @@ -580,7 +580,7 @@ public ModuleFormConfigDTO getBusinessFormConfig(String organizationId) { } /** - * 由审批执行操作统一调用, 勿修改 + * ⚠️反射调用: 由审批执行操作统一调用, 勿修改 * @param param 参数 */ public void updateSnapshotApprovalStatus(ResourceSnapshotApprovalParam param) { diff --git a/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractService.java b/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractService.java index e12b6c2ff1..153a1e16f8 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/contract/service/ContractService.java @@ -679,7 +679,7 @@ private void updateStatusSnapshot(String id, String stage, String approvalStatus } /** - * 由审批执行操作统一调用, 勿修改 + * ⚠️反射调用: 由审批执行操作统一调用, 勿修改 * @param param 参数 */ public void updateSnapshotApprovalStatus(ResourceSnapshotApprovalParam param) { diff --git a/backend/crm/src/main/java/cn/cordys/crm/opportunity/service/OpportunityQuotationService.java b/backend/crm/src/main/java/cn/cordys/crm/opportunity/service/OpportunityQuotationService.java index 40909f815e..a96725acf6 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/opportunity/service/OpportunityQuotationService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/opportunity/service/OpportunityQuotationService.java @@ -458,7 +458,7 @@ private void updateSnapshot(String id, String approvalStatus, ModuleFormConfigDT } /** - * 由审批执行操作统一调用, 勿修改 + * ⚠️反射调用: 由审批执行操作统一调用, 勿修改 * @param param 参数 */ public void updateSnapshotApprovalStatus(ResourceSnapshotApprovalParam param) { diff --git a/backend/crm/src/main/java/cn/cordys/crm/order/service/OrderService.java b/backend/crm/src/main/java/cn/cordys/crm/order/service/OrderService.java index db1910c458..aae6b3d69e 100644 --- a/backend/crm/src/main/java/cn/cordys/crm/order/service/OrderService.java +++ b/backend/crm/src/main/java/cn/cordys/crm/order/service/OrderService.java @@ -29,8 +29,11 @@ import cn.cordys.crm.approval.constants.ApprovalFormTypeEnum; import cn.cordys.crm.approval.constants.ApprovalStatus; import cn.cordys.crm.approval.constants.ExecuteTimingEnum; +import cn.cordys.crm.approval.dto.ResourceSnapshotApprovalParam; import cn.cordys.crm.approval.service.ApprovalFlowService; import cn.cordys.crm.contract.domain.Contract; +import cn.cordys.crm.contract.domain.ContractSnapshot; +import cn.cordys.crm.contract.dto.response.ContractGetResponse; import cn.cordys.crm.customer.domain.Customer; import cn.cordys.crm.order.domain.Order; import cn.cordys.crm.order.domain.OrderSnapshot; @@ -446,6 +449,22 @@ public OrderGetResponse getSnapshot(String id) { return response; } + /** + * ⚠️反射调用: 由审批执行操作统一调用, 勿修改 + * @param param 参数 + */ + public void updateSnapshotApprovalStatus(ResourceSnapshotApprovalParam param) { + OrderSnapshot snapshotCriteria = new OrderSnapshot(); + snapshotCriteria.setOrderId(param.getResourceId()); + OrderSnapshot snapshot = snapshotBaseMapper.selectOne(snapshotCriteria); + if (snapshot != null) { + OrderGetResponse response = JSON.parseObject(snapshot.getOrderValue(), OrderGetResponse.class); + response.setApprovalStatus(param.getApprovalStatus()); + snapshot.setOrderValue(JSON.toJSONString(response)); + snapshotBaseMapper.update(snapshot); + } + } + /** * 订单列表 diff --git a/backend/crm/src/main/resources/i18n/cordys-crm_en_US.properties b/backend/crm/src/main/resources/i18n/cordys-crm_en_US.properties index aa775d8929..3581b4590f 100644 --- a/backend/crm/src/main/resources/i18n/cordys-crm_en_US.properties +++ b/backend/crm/src/main/resources/i18n/cordys-crm_en_US.properties @@ -851,3 +851,4 @@ no.revoke.approval=Cannot revoke no.approval.next.node=No subsequent node found, check the approval flow configuration auto.approval.passed=Auto passed auto.approval.rejected=Auto rejected +no.approval.instance=No approval instance! diff --git a/backend/crm/src/main/resources/i18n/cordys-crm_zh_CN.properties b/backend/crm/src/main/resources/i18n/cordys-crm_zh_CN.properties index add1f96097..71797c86d4 100644 --- a/backend/crm/src/main/resources/i18n/cordys-crm_zh_CN.properties +++ b/backend/crm/src/main/resources/i18n/cordys-crm_zh_CN.properties @@ -849,4 +849,5 @@ reject_approval=驳回审批 no.revoke.approval=无法撤销 no.approval.next.node=未找到后续节点,请检查审批流配置 auto.approval.passed=自动通过 -auto.approval.rejected=自动驳回 \ No newline at end of file +auto.approval.rejected=自动驳回 +no.approval.instance=审批实例为空! \ No newline at end of file