| | |
| | | -- 因此先按主键补插父目录;已存在时仅恢复删除标记,不改动原有名称和路径。 |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | VALUES |
| | | (1065864, '能耗管理', '', 1, 16, 0, '/energyManagement', 'monitor', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0') |
| | | ON DUPLICATE KEY UPDATE `deleted` = b'0', `status` = 0, `visible` = b'1', `updater` = '1', `update_time` = NOW(); |
| | | (1065864, '能耗管理', '', 1, 16, 0, '/energyManagement', 'ep:lightning', NULL, NULL, 0, b'1', b'1', b'1', '1', NOW(), '1', NOW(), b'0') |
| | | ON DUPLICATE KEY UPDATE `icon` = 'ep:lightning', `deleted` = b'0', `status` = 0, `visible` = b'1', `updater` = '1', `update_time` = NOW(); |
| | | |
| | | INSERT INTO `system_menu` (`id`, `name`, `permission`, `type`, `sort`, `parent_id`, `path`, `icon`, `component`, `component_name`, `status`, `visible`, `keep_alive`, `always_show`, `creator`, `create_time`, `updater`, `update_time`, `deleted`) |
| | | VALUES |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.aftersales.controller.admin.compensation.vo.AfterSaleCompensationPageReqVO; |
| | | import cn.iocoder.yudao.module.aftersales.dal.dataobject.compensation.AfterSaleCompensationDO; |
| | | import cn.iocoder.yudao.module.aftersales.enums.AfterSaleCompensationAuditStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<AfterSaleCompensationDO>() |
| | | .eq(AfterSaleCompensationDO::getId, id) |
| | | .in(AfterSaleCompensationDO::getAuditStatus, |
| | | AfterSaleCompensationAuditStatusEnum.DRAFT.getStatus(), |
| | | AfterSaleCompensationAuditStatusEnum.REJECT.getStatus()) |
| | | .set(AfterSaleCompensationDO::getAuditStatus, status) |
| | | .set(AfterSaleCompensationDO::getReviewerId, null) |
| | | .set(AfterSaleCompensationDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<AfterSaleCompensationDO>() |
| | | .eq(AfterSaleCompensationDO::getId, id) |
| | | .eq(AfterSaleCompensationDO::getAuditStatus, |
| | | AfterSaleCompensationAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(AfterSaleCompensationDO::getAuditStatus, status) |
| | | .set(AfterSaleCompensationDO::getReviewerId, reviewerId) |
| | | .set(AfterSaleCompensationDO::getReviewerName, reviewerName) |
| | |
| | | ErrorCode COMPENSATION_DELETE_FAIL_NOT_DRAFT = new ErrorCode(1_022_004_004, "赔付单不是草稿状态,无法删除"); |
| | | ErrorCode COMPENSATION_TICKET_NOT_EXISTS = new ErrorCode(1_022_004_005, "关联的售后工单不存在"); |
| | | ErrorCode COMPENSATION_AUDIT_REJECT_REASON_REQUIRED = new ErrorCode(1_022_004_006, "审核不通过时必须填写不通过原因"); |
| | | ErrorCode COMPENSATION_UPDATE_FAIL_NOT_EDITABLE = new ErrorCode(1_022_004_007, "只有未提交或审核不通过状态的赔付单才能修改"); |
| | | |
| | | } |
| | |
| | | if (exists == null) { |
| | | throw exception(ErrorCodeConstants.COMPENSATION_NOT_EXISTS); |
| | | } |
| | | if (ObjUtil.notEqual(exists.getAuditStatus(), AfterSaleCompensationAuditStatusEnum.DRAFT.getStatus())) { |
| | | throw exception(ErrorCodeConstants.COMPENSATION_DELETE_FAIL_NOT_DRAFT); |
| | | if (ObjUtil.notEqual(exists.getAuditStatus(), AfterSaleCompensationAuditStatusEnum.DRAFT.getStatus()) |
| | | && ObjUtil.notEqual(exists.getAuditStatus(), AfterSaleCompensationAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(ErrorCodeConstants.COMPENSATION_UPDATE_FAIL_NOT_EDITABLE); |
| | | } |
| | | AfterSaleCompensationDO entity = BeanUtils.toBean(updateReqVO, AfterSaleCompensationDO.class, req -> req |
| | | .setCompensationNo(exists.getCompensationNo()) |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(COMPENSATION_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | compensationMapper.submitAndResetAuditInfo(id, AfterSaleCompensationAuditStatusEnum.PROCESS.getStatus()); |
| | | if (compensationMapper.submitAndResetAuditInfo(id, |
| | | AfterSaleCompensationAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(ErrorCodeConstants.COMPENSATION_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(ErrorCodeConstants.COMPENSATION_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | compensationMapper.auditCompensation(id, AfterSaleCompensationAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (compensationMapper.auditCompensation(id, AfterSaleCompensationAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ErrorCodeConstants.COMPENSATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | compensationMapper.auditCompensation(id, AfterSaleCompensationAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (compensationMapper.auditCompensation(id, AfterSaleCompensationAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ErrorCodeConstants.COMPENSATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | // 6. 审核通过后的后置业务逻辑:当前赔付单审批通过后无自动生成下游单据的动作, |
| | | // 支付状态(payStatus)待后续接入财务模块时再联动。 |
| | | } |
| | |
| | | if (historicProcessInstance == null) { |
| | | throw exception(PROCESS_INSTANCE_NOT_EXISTS); |
| | | } |
| | | AdminUserRespDTO startUser = adminUserApi.getUser(Long.valueOf(historicProcessInstance.getStartUserId())); |
| | | DeptRespDTO dept = deptApi.getDept(startUser.getDeptId()); |
| | | // 发起人 / 部门可能不存在(历史数据、用户已删除),需做空值保护 |
| | | AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(historicProcessInstance.getStartUserId())); |
| | | DeptRespDTO dept = startUser != null && startUser.getDeptId() != null |
| | | ? deptApi.getDept(startUser.getDeptId()) : null; |
| | | List<HistoricTaskInstance> tasks = taskService.getFinishedTaskListByProcessInstanceIdWithoutCancel(processInstanceId); |
| | | Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap( |
| | | convertSet(tasks, item -> Long.valueOf(item.getAssignee()))); |
| | | convertSet(tasks, item -> NumberUtils.parseLong(item.getAssignee()))); |
| | | UserSimpleBaseVO startUserVO = new UserSimpleBaseVO(); |
| | | if (startUser != null) { |
| | | startUserVO.setNickname(startUser.getNickname()); |
| | | } |
| | | if (dept != null) { |
| | | startUserVO.setDeptName(dept.getName()); |
| | | } |
| | | BpmProcessPrintDataRespVO printData = BpmProcessInstanceConvert.INSTANCE.buildProcessInstancePrintData( |
| | | historicProcessInstance, |
| | | processDefinitionService.getProcessDefinitionInfo(historicProcessInstance.getProcessDefinitionId()), |
| | | tasks, userMap, |
| | | new UserSimpleBaseVO().setNickname(startUser.getNickname()).setDeptName(dept.getName())); |
| | | tasks, userMap, startUserVO); |
| | | // 填充业务附件配置,实现打印自动展示外部业务信息 |
| | | businessAttachService.fillBusinessForm(printData.getProcessInstance().getProcessDefinition(), |
| | | processDefinitionService.getProcessDefinition(historicProcessInstance.getProcessDefinitionId()).getKey(), |
| | |
| | | return null; |
| | | } |
| | | |
| | | // 解析表单配置 |
| | | // 解析表单配置。部分历史流程定义没有配置表单字段(form_fields 为空),此时无法生成摘要,直接返回 |
| | | if (ObjectUtil.isEmpty(processDefinitionInfo.getFormFields())) { |
| | | return null; |
| | | } |
| | | Map<String, BpmFormFieldVO> formFieldsMap = new LinkedHashMap<>(); |
| | | processDefinitionInfo.getFormFields().forEach(formFieldStr -> { |
| | | JsonNode formFieldNode = JsonUtils.parseObject(formFieldStr, JsonNode.class); |
| | |
| | | |
| | | @GetMapping("/page-by-customer") |
| | | @Operation(summary = "获得合同分页,基于指定客户") |
| | | @PreAuthorize("@ss.hasPermission('crm:contract:query')") |
| | | public CommonResult<PageResult<CrmContractRespVO>> getContractPageByCustomer(@Valid CrmContractPageReqVO pageVO) { |
| | | Assert.notNull(pageVO.getCustomerId(), "客户编号不能为空"); |
| | | PageResult<CrmContractDO> pageResult = contractService.getContractPageByCustomerId(pageVO); |
| | |
| | | |
| | | @GetMapping("/page-by-business") |
| | | @Operation(summary = "获得合同分页,基于指定商机") |
| | | @PreAuthorize("@ss.hasPermission('crm:contract:query')") |
| | | public CommonResult<PageResult<CrmContractRespVO>> getContractPageByBusiness(@Valid CrmContractPageReqVO pageVO) { |
| | | Assert.notNull(pageVO.getBusinessId(), "商机编号不能为空"); |
| | | PageResult<CrmContractDO> pageResult = contractService.getContractPageByBusinessId(pageVO); |
| | |
| | | |
| | | @GetMapping("/page-by-customer") |
| | | @Operation(summary = "获得开票分页,基于指定客户") |
| | | @PreAuthorize("@ss.hasPermission('crm:invoice:query')") |
| | | public CommonResult<PageResult<CrmInvoiceRespVO>> getInvoicePageByCustomer(@Valid CrmInvoicePageReqVO pageReqVO) { |
| | | Assert.notNull(pageReqVO.getCustomerId(), "客户编号不能为空"); |
| | | PageResult<CrmInvoiceDO> pageResult = invoiceService.getInvoicePageByCustomerId(pageReqVO); |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.cancellation.vo.CrmCancellationPageReqVO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.cancellation.CrmCancellationDO; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<CrmCancellationDO>() |
| | | .eq(CrmCancellationDO::getId, id) |
| | | .in(CrmCancellationDO::getAuditStatus, CrmAuditStatusEnum.DRAFT.getStatus(), |
| | | CrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(CrmCancellationDO::getAuditStatus, status) |
| | | .set(CrmCancellationDO::getReviewerId, null) |
| | | .set(CrmCancellationDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<CrmCancellationDO>() |
| | | .eq(CrmCancellationDO::getId, id) |
| | | .eq(CrmCancellationDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(CrmCancellationDO::getAuditStatus, status) |
| | | .set(CrmCancellationDO::getReviewerId, reviewerId) |
| | | .set(CrmCancellationDO::getReviewerName, reviewerName) |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<CrmContractDO>() |
| | | .eq(CrmContractDO::getId, id) |
| | | .in(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.DRAFT.getStatus(), |
| | | CrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(CrmContractDO::getAuditStatus, status) |
| | | .set(CrmContractDO::getReviewerId, null) |
| | | .set(CrmContractDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<CrmContractDO>() |
| | | .eq(CrmContractDO::getId, id) |
| | | .eq(CrmContractDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(CrmContractDO::getAuditStatus, status) |
| | | .set(CrmContractDO::getReviewerId, reviewerId) |
| | | .set(CrmContractDO::getReviewerName, reviewerName) |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<CrmInvoiceDO>() |
| | | .eq(CrmInvoiceDO::getId, id) |
| | | .in(CrmInvoiceDO::getAuditStatus, CrmAuditStatusEnum.DRAFT.getStatus(), |
| | | CrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(CrmInvoiceDO::getAuditStatus, status) |
| | | .set(CrmInvoiceDO::getReviewerId, null) |
| | | .set(CrmInvoiceDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<CrmInvoiceDO>() |
| | | .eq(CrmInvoiceDO::getId, id) |
| | | .eq(CrmInvoiceDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(CrmInvoiceDO::getAuditStatus, status) |
| | | .set(CrmInvoiceDO::getReviewerId, reviewerId) |
| | | .set(CrmInvoiceDO::getReviewerName, reviewerName) |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.crm.controller.admin.refund.vo.CrmRefundPageReqVO; |
| | | import cn.iocoder.yudao.module.crm.dal.dataobject.refund.CrmRefundDO; |
| | | import cn.iocoder.yudao.module.crm.enums.common.CrmAuditStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<CrmRefundDO>() |
| | | .eq(CrmRefundDO::getId, id) |
| | | .in(CrmRefundDO::getAuditStatus, CrmAuditStatusEnum.DRAFT.getStatus(), |
| | | CrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(CrmRefundDO::getAuditStatus, status) |
| | | .set(CrmRefundDO::getReviewerId, null) |
| | | .set(CrmRefundDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<CrmRefundDO>() |
| | | .eq(CrmRefundDO::getId, id) |
| | | .eq(CrmRefundDO::getAuditStatus, CrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(CrmRefundDO::getAuditStatus, status) |
| | | .set(CrmRefundDO::getReviewerId, reviewerId) |
| | | .set(CrmRefundDO::getReviewerName, reviewerName) |
| | |
| | | ErrorCode CONTRACT_SUBMIT_FAIL_NOT_EDITABLE = new ErrorCode(1_020_000_010, "只有未提交或审核不通过状态的合同才能提交审批"); |
| | | ErrorCode CONTRACT_AUDIT_FAIL_NOT_PROCESS = new ErrorCode(1_020_000_012, "只有审批中状态的合同才能审核"); |
| | | ErrorCode CONTRACT_AUDIT_REJECT_REASON_REQUIRED = new ErrorCode(1_020_000_014, "审核不通过时必须填写不通过原因"); |
| | | ErrorCode CONTRACT_DELETE_FAIL_NOT_EDITABLE = new ErrorCode(1_020_000_015, "只有未提交或审核不通过状态的合同才能删除"); |
| | | ErrorCode CONTRACT_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_020_000_009, "导入合同数据不能为空!"); |
| | | ErrorCode CONTRACT_NAME_EXISTS = new ErrorCode(1_020_000_011, "已存在合同【{}】,且未开启覆盖!"); |
| | | ErrorCode CONTRACT_IMPORT_CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_000_013, "客户【{}】不存在!"); |
| | |
| | | ErrorCode CRM_CREDIT_RATING_IMPORT_CUSTOMER_NOT_EXISTS = new ErrorCode(1_020_018_020, "客户【{}】不存在!"); |
| | | ErrorCode CRM_CREDIT_RATING_NAME_EXISTS = new ErrorCode(1_020_018_021, "已存在客户【{}】的信用评级,且未开启覆盖!"); |
| | | |
| | | ErrorCode CRM_REFUND_UPDATE_FAIL_NOT_EDITABLE = new ErrorCode(1_020_018_022, "只有草稿或审核不通过状态的退费单才能修改"); |
| | | ErrorCode CRM_REFUND_DELETE_FAIL_NOT_EDITABLE = new ErrorCode(1_020_018_023, "只有草稿或审核不通过状态的退费单才能删除"); |
| | | ErrorCode CRM_CANCELLATION_UPDATE_FAIL_NOT_EDITABLE = new ErrorCode(1_020_018_024, "只有草稿或审核不通过状态的销户申请才能修改"); |
| | | ErrorCode CRM_CANCELLATION_DELETE_FAIL_NOT_EDITABLE = new ErrorCode(1_020_018_025, "只有草稿或审核不通过状态的销户申请才能删除"); |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.module.system.api.approval.ApprovalConfigApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | |
| | | @Override |
| | | public void updateCancellation(CrmCancellationSaveReqVO updateReqVO) { |
| | | // 1. 校验存在 + 审核通过的销户申请不允许修改 |
| | | // 1. 校验存在 + 只有草稿、审核不通过可以修改 |
| | | CrmCancellationDO cancellation = validateCancellationExists(updateReqVO.getId()); |
| | | if (ObjUtil.equal(cancellation.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { |
| | | throw exception(ErrorCodeConstants.CRM_CANCELLATION_UPDATE_FAIL_APPROVE); |
| | | if (ObjUtil.notEqual(cancellation.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && ObjUtil.notEqual(cancellation.getAuditStatus(), CrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(ErrorCodeConstants.CRM_CANCELLATION_UPDATE_FAIL_NOT_EDITABLE); |
| | | } |
| | | // 2. 更新销户申请 |
| | | // 2. 更新销户申请;审批状态与审核结果只能由提交/审核变更,此处显式清空 |
| | | CrmCancellationDO entity = BeanUtils.toBean(updateReqVO, CrmCancellationDO.class); |
| | | entity.setAuditStatus(null); // 审批状态只能由提交/审核变更 |
| | | cancellationMapper.updateById(entity); |
| | | // 审核相关字段只能由提交/审核变更 |
| | | entity.setAuditStatus(null); |
| | | entity.setReviewerId(null); |
| | | entity.setReviewerName(null); |
| | | entity.setReviewTime(null); |
| | | entity.setReviewRemark(null); |
| | | cancellationMapper.update(entity, new LambdaUpdateWrapper<CrmCancellationDO>() |
| | | .eq(CrmCancellationDO::getId, entity.getId()) |
| | | .set(CrmCancellationDO::getAuditStatus, null) |
| | | .set(CrmCancellationDO::getReviewerId, null) |
| | | .set(CrmCancellationDO::getReviewerName, null) |
| | | .set(CrmCancellationDO::getReviewTime, null) |
| | | .set(CrmCancellationDO::getReviewRemark, null)); |
| | | } |
| | | |
| | | @Override |
| | | public void deleteCancellation(Long id) { |
| | | // 校验存在 + 审核通过的销户申请不允许删除 |
| | | // 校验存在 + 只有草稿、审核不通过可以删除 |
| | | CrmCancellationDO cancellation = validateCancellationExists(id); |
| | | if (ObjUtil.equal(cancellation.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { |
| | | throw exception(ErrorCodeConstants.CRM_CANCELLATION_DELETE_FAIL_APPROVE); |
| | | if (ObjUtil.notEqual(cancellation.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && ObjUtil.notEqual(cancellation.getAuditStatus(), CrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(ErrorCodeConstants.CRM_CANCELLATION_DELETE_FAIL_NOT_EDITABLE); |
| | | } |
| | | cancellationMapper.deleteById(id); |
| | | } |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(CANCELLATION_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | cancellationMapper.submitAndResetAuditInfo(id, CrmAuditStatusEnum.PROCESS.getStatus()); |
| | | if (cancellationMapper.submitAndResetAuditInfo(id, CrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(ErrorCodeConstants.CRM_CANCELLATION_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(ErrorCodeConstants.CRM_CANCELLATION_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | cancellationMapper.auditCancellation(id, CrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (cancellationMapper.auditCancellation(id, CrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ErrorCodeConstants.CRM_CANCELLATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | cancellationMapper.auditCancellation(id, CrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (cancellationMapper.auditCancellation(id, CrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ErrorCodeConstants.CRM_CANCELLATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | } |
| | | |
| | | private CrmCancellationDO validateCancellationExists(Long id) { |
| | |
| | | updateReqVO.setOwnerUserId(null); // 不允许更新的字段 |
| | | // 1.1 校验存在 |
| | | CrmContractDO oldContract = validateContractExists(updateReqVO.getId()); |
| | | // 1.2 只有草稿、审批中,可以编辑; |
| | | // 1.2 只有草稿、审核不通过,可以编辑; |
| | | if (!ObjectUtils.equalsAny(oldContract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), |
| | | CrmAuditStatusEnum.PROCESS.getStatus())) { |
| | | CrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(CONTRACT_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | // 1.3 校验产品项的有效性 |
| | |
| | | public void deleteContract(Long id) { |
| | | // 1.1 校验存在 |
| | | CrmContractDO contract = validateContractExists(id); |
| | | // 1.2 如果被 CrmReceivableDO 所使用,则不允许删除 |
| | | // 1.2 只有草稿、审核不通过,可以删除; |
| | | if (!ObjectUtils.equalsAny(contract.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), |
| | | CrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(CONTRACT_DELETE_FAIL_NOT_EDITABLE); |
| | | } |
| | | // 1.3 如果被 CrmReceivableDO 所使用,则不允许删除 |
| | | if (receivableService.getReceivableCountByContractId(contract.getId()) > 0) { |
| | | throw exception(CONTRACT_DELETE_FAIL); |
| | | } |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @LogRecord(type = CRM_CONTRACT_TYPE, subType = CRM_CONTRACT_SUBMIT_SUB_TYPE, bizNo = "{{#id}}", |
| | | success = CRM_CONTRACT_SUBMIT_SUCCESS) |
| | | @CrmPermission(bizType = CrmBizTypeEnum.CRM_CONTRACT, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) |
| | | public void submitContract(Long id) { |
| | | // 1. 校验存在 + 可提交状态(未提交 / 审核不通过) |
| | | CrmContractDO contract = validateContractExists(id); |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(CONTRACT_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | contractMapper.submitAndResetAuditInfo(id, CrmAuditStatusEnum.PROCESS.getStatus()); |
| | | if (contractMapper.submitAndResetAuditInfo(id, CrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(CONTRACT_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | |
| | | // 4. 记录日志 |
| | | LogRecordContext.putVariable("contractName", contract.getName()); |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(CONTRACT_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | contractMapper.auditContract(id, CrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (contractMapper.auditContract(id, CrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(CONTRACT_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | contractMapper.auditContract(id, CrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (contractMapper.auditContract(id, CrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(CONTRACT_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | } |
| | | |
| | | // ======================= 查询相关 ======================= |
| | |
| | | // 1.2 校验可开票金额超过上限 |
| | | validateInvoicePriceExceedsLimit(updateReqVO); |
| | | |
| | | // 1.3 只有草稿、审批中,可以编辑; |
| | | // 1.3 只有草稿、审核不通过,可以编辑; |
| | | if (!ObjectUtils.equalsAny(oldInvoice.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus(), |
| | | CrmAuditStatusEnum.PROCESS.getStatus())) { |
| | | CrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(INVOICE_UPDATE_FAIL_EDITING_PROHIBITED); |
| | | } |
| | | |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | @LogRecord(type = CRM_INVOICE_TYPE, subType = CRM_INVOICE_SUBMIT_SUB_TYPE, bizNo = "{{#id}}", |
| | | success = CRM_INVOICE_SUBMIT_SUCCESS) |
| | | @CrmPermission(bizType = CrmBizTypeEnum.CRM_INVOICE, bizId = "#id", level = CrmPermissionLevelEnum.WRITE) |
| | | public void submitInvoice(Long id) { |
| | | // 1. 校验存在 + 可提交状态(未提交 / 审核不通过) |
| | | CrmInvoiceDO invoice = validateInvoiceExists(id); |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(INVOICE_APPROVE_BIZ_TYPE); |
| | | |
| | | // 4. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | invoiceMapper.submitAndResetAuditInfo(id, CrmAuditStatusEnum.PROCESS.getStatus()); |
| | | if (invoiceMapper.submitAndResetAuditInfo(id, CrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(INVOICE_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | |
| | | // 5. 记录日志 |
| | | LogRecordContext.putVariable("invoiceNo", invoice.getNo()); |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(INVOICE_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | invoiceMapper.auditInvoice(id, CrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (invoiceMapper.auditInvoice(id, CrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(INVOICE_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | // (开票无额外后置业务逻辑,审批通过后即可用于创建回款 / 关联开票选择) |
| | | invoiceMapper.auditInvoice(id, CrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (invoiceMapper.auditInvoice(id, CrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(INVOICE_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | import cn.iocoder.yudao.module.system.api.approval.ApprovalConfigApi; |
| | | import cn.iocoder.yudao.module.system.api.user.AdminUserApi; |
| | | import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | |
| | | |
| | | @Override |
| | | public void updateRefund(CrmRefundSaveReqVO updateReqVO) { |
| | | // 1. 校验存在 + 审核通过的退费单不允许修改 |
| | | // 1. 校验存在 + 只有草稿、审核不通过可以修改 |
| | | CrmRefundDO refund = validateRefundExists(updateReqVO.getId()); |
| | | if (ObjUtil.equal(refund.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { |
| | | throw exception(ErrorCodeConstants.CRM_REFUND_UPDATE_FAIL_APPROVE); |
| | | if (ObjUtil.notEqual(refund.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && ObjUtil.notEqual(refund.getAuditStatus(), CrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(ErrorCodeConstants.CRM_REFUND_UPDATE_FAIL_NOT_EDITABLE); |
| | | } |
| | | // 2. 更新退费单 |
| | | // 2. 更新退费单;审批状态与审核结果只能由提交/审核变更,此处显式清空 |
| | | CrmRefundDO entity = BeanUtils.toBean(updateReqVO, CrmRefundDO.class); |
| | | entity.setAuditStatus(null); // 审批状态只能由提交/审核变更 |
| | | refundMapper.updateById(entity); |
| | | // 审核相关字段只能由提交/审核变更 |
| | | entity.setAuditStatus(null); |
| | | entity.setReviewerId(null); |
| | | entity.setReviewerName(null); |
| | | entity.setReviewTime(null); |
| | | entity.setReviewRemark(null); |
| | | refundMapper.update(entity, new LambdaUpdateWrapper<CrmRefundDO>() |
| | | .eq(CrmRefundDO::getId, entity.getId()) |
| | | .set(CrmRefundDO::getAuditStatus, null) |
| | | .set(CrmRefundDO::getReviewerId, null) |
| | | .set(CrmRefundDO::getReviewerName, null) |
| | | .set(CrmRefundDO::getReviewTime, null) |
| | | .set(CrmRefundDO::getReviewRemark, null)); |
| | | } |
| | | |
| | | @Override |
| | | public void deleteRefund(Long id) { |
| | | // 校验存在 + 审核通过的退费单不允许删除 |
| | | // 校验存在 + 只有草稿、审核不通过可以删除 |
| | | CrmRefundDO refund = validateRefundExists(id); |
| | | if (ObjUtil.equal(refund.getAuditStatus(), CrmAuditStatusEnum.APPROVE.getStatus())) { |
| | | throw exception(ErrorCodeConstants.CRM_REFUND_DELETE_FAIL_APPROVE); |
| | | if (ObjUtil.notEqual(refund.getAuditStatus(), CrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && ObjUtil.notEqual(refund.getAuditStatus(), CrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(ErrorCodeConstants.CRM_REFUND_DELETE_FAIL_NOT_EDITABLE); |
| | | } |
| | | refundMapper.deleteById(id); |
| | | } |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(REFUND_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | refundMapper.submitAndResetAuditInfo(id, CrmAuditStatusEnum.PROCESS.getStatus()); |
| | | if (refundMapper.submitAndResetAuditInfo(id, CrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(ErrorCodeConstants.CRM_REFUND_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(ErrorCodeConstants.CRM_REFUND_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | refundMapper.auditRefund(id, CrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (refundMapper.auditRefund(id, CrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ErrorCodeConstants.CRM_REFUND_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | refundMapper.auditRefund(id, CrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (refundMapper.auditRefund(id, CrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ErrorCodeConstants.CRM_REFUND_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | } |
| | | |
| | | private CrmRefundDO validateRefundExists(Long id) { |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<ErpFinancePaymentDO>() |
| | | .eq(ErpFinancePaymentDO::getId, id) |
| | | .eq(ErpFinancePaymentDO::getStatus, ErpAuditStatus.PROCESS.getStatus()) |
| | | .set(ErpFinancePaymentDO::getStatus, status) |
| | | .set(ErpFinancePaymentDO::getReviewerId, null) |
| | | .set(ErpFinancePaymentDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<ErpFinancePaymentDO>() |
| | | .eq(ErpFinancePaymentDO::getId, id) |
| | | .eq(ErpFinancePaymentDO::getStatus, ErpAuditStatus.APPROVING.getStatus()) |
| | | .set(ErpFinancePaymentDO::getStatus, status) |
| | | .set(ErpFinancePaymentDO::getReviewerId, reviewerId) |
| | | .set(ErpFinancePaymentDO::getReviewerName, reviewerName) |
| | |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderDO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseOrderItemDO; |
| | | import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; |
| | | import cn.iocoder.yudao.module.erp.enums.ErpPurchaseOrderStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<ErpPurchaseOrderDO>() |
| | | .eq(ErpPurchaseOrderDO::getId, id) |
| | | .in(ErpPurchaseOrderDO::getStatus, |
| | | ErpPurchaseOrderStatusEnum.DRAFT.getStatus(), ErpPurchaseOrderStatusEnum.REJECT.getStatus()) |
| | | .set(ErpPurchaseOrderDO::getStatus, status) |
| | | .set(ErpPurchaseOrderDO::getReviewerId, null) |
| | | .set(ErpPurchaseOrderDO::getReviewerName, null) |
| | |
| | | default int auditPurchaseOrder(Long id, Integer status, Long reviewerId, String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<ErpPurchaseOrderDO>() |
| | | .eq(ErpPurchaseOrderDO::getId, id) |
| | | .eq(ErpPurchaseOrderDO::getStatus, ErpPurchaseOrderStatusEnum.PROCESS.getStatus()) |
| | | .set(ErpPurchaseOrderDO::getStatus, status) |
| | | .set(ErpPurchaseOrderDO::getReviewerId, reviewerId) |
| | | .set(ErpPurchaseOrderDO::getReviewerName, reviewerName) |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.plan.ErpPurchasePlanPageReqVO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchasePlanDO; |
| | | import cn.iocoder.yudao.module.erp.enums.ErpPurchasePlanStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<ErpPurchasePlanDO>() |
| | | .eq(ErpPurchasePlanDO::getId, id) |
| | | .in(ErpPurchasePlanDO::getStatus, |
| | | ErpPurchasePlanStatusEnum.DRAFT.getStatus(), ErpPurchasePlanStatusEnum.REJECT.getStatus()) |
| | | .set(ErpPurchasePlanDO::getStatus, status) |
| | | .set(ErpPurchasePlanDO::getReviewerId, null) |
| | | .set(ErpPurchasePlanDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<ErpPurchasePlanDO>() |
| | | .eq(ErpPurchasePlanDO::getId, id) |
| | | .eq(ErpPurchasePlanDO::getStatus, ErpPurchasePlanStatusEnum.PROCESS.getStatus()) |
| | | .set(ErpPurchasePlanDO::getStatus, status) |
| | | .set(ErpPurchasePlanDO::getReviewerId, reviewerId) |
| | | .set(ErpPurchasePlanDO::getReviewerName, reviewerName) |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.erp.controller.admin.purchase.vo.request.ErpPurchaseRequestPageReqVO; |
| | | import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpPurchaseRequestDO; |
| | | import cn.iocoder.yudao.module.erp.enums.ErpPurchaseRequestStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<ErpPurchaseRequestDO>() |
| | | .eq(ErpPurchaseRequestDO::getId, id) |
| | | .in(ErpPurchaseRequestDO::getStatus, |
| | | ErpPurchaseRequestStatusEnum.DRAFT.getStatus(), ErpPurchaseRequestStatusEnum.REJECT.getStatus()) |
| | | .set(ErpPurchaseRequestDO::getStatus, status) |
| | | .set(ErpPurchaseRequestDO::getReviewerId, null) |
| | | .set(ErpPurchaseRequestDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<ErpPurchaseRequestDO>() |
| | | .eq(ErpPurchaseRequestDO::getId, id) |
| | | .eq(ErpPurchaseRequestDO::getStatus, ErpPurchaseRequestStatusEnum.PROCESS.getStatus()) |
| | | .set(ErpPurchaseRequestDO::getStatus, status) |
| | | .set(ErpPurchaseRequestDO::getReviewerId, reviewerId) |
| | | .set(ErpPurchaseRequestDO::getReviewerName, reviewerName) |
| | |
| | | // 2. 校验审批配置已启用且配置了有效审批人 |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(FINANCE_PAYMENT_APPROVE_BIZ_TYPE); |
| | | // 3. 状态置为审批中,并清空上一轮审核结果 |
| | | financePaymentMapper.submitAndResetAuditInfo(id, ErpAuditStatus.APPROVING.getStatus()); |
| | | if (financePaymentMapper.submitAndResetAuditInfo(id, ErpAuditStatus.APPROVING.getStatus()) != 1) { |
| | | throw exception(FINANCE_PAYMENT_SUBMIT_FAIL_NOT_ALLOWED); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(FINANCE_PAYMENT_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | financePaymentMapper.auditFinancePayment(id, ErpAuditStatus.PROCESS.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (financePaymentMapper.auditFinancePayment(id, ErpAuditStatus.PROCESS.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(FINANCE_PAYMENT_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为已审核 |
| | | financePaymentMapper.auditFinancePayment(id, ErpAuditStatus.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (financePaymentMapper.auditFinancePayment(id, ErpAuditStatus.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(FINANCE_PAYMENT_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(PURCHASE_ORDER_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 置为审批中,并清空上一轮审核信息,避免驳回原因残留 |
| | | purchaseOrderMapper.submitAndResetAuditInfo(id, ErpPurchaseOrderStatusEnum.PROCESS.getStatus()); |
| | | if (purchaseOrderMapper.submitAndResetAuditInfo(id, ErpPurchaseOrderStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(PURCHASE_ORDER_SUBMIT_FAIL_NOT_ALLOWED); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(PURCHASE_ORDER_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | purchaseOrderMapper.auditPurchaseOrder(id, ErpPurchaseOrderStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (purchaseOrderMapper.auditPurchaseOrder(id, ErpPurchaseOrderStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(PURCHASE_ORDER_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | |
| | | // 3. 审核通过 |
| | | purchaseOrderMapper.auditPurchaseOrder(id, ErpPurchaseOrderStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (purchaseOrderMapper.auditPurchaseOrder(id, ErpPurchaseOrderStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(PURCHASE_ORDER_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | return; |
| | | } |
| | | purchaseOrders.forEach(purchaseOrder -> { |
| | | if (ErpAuditStatus.APPROVE.getStatus().equals(purchaseOrder.getStatus())) { |
| | | if (ErpPurchaseOrderStatusEnum.APPROVE.getStatus().equals(purchaseOrder.getStatus())) { |
| | | throw exception(PURCHASE_ORDER_DELETE_FAIL_APPROVE, purchaseOrder.getNo()); |
| | | } |
| | | // 审批中禁止删除,需先由审批人「审核不通过」退回 |
| | | if (ErpPurchaseOrderStatusEnum.PROCESS.getStatus().equals(purchaseOrder.getStatus())) { |
| | | throw exception(PURCHASE_ORDER_UPDATE_FAIL_PROCESS, purchaseOrder.getNo()); |
| | | } |
| | | }); |
| | | |
| | | // 2. 遍历删除 |
| | |
| | | // 3. 校验审批配置已启用且配置了有效审批人(未配置时抛出带明确提示的业务异常) |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(PURCHASE_PLAN_APPROVE_BIZ_TYPE); |
| | | // 4. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | purchasePlanMapper.submitAndResetAuditInfo(id, ErpPurchasePlanStatusEnum.PROCESS.getStatus()); |
| | | if (purchasePlanMapper.submitAndResetAuditInfo(id, ErpPurchasePlanStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(PURCHASE_PLAN_SUBMIT_FAIL_NOT_ALLOWED); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(PURCHASE_PLAN_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | purchasePlanMapper.auditPurchasePlan(id, ErpPurchasePlanStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (purchasePlanMapper.auditPurchasePlan(id, ErpPurchasePlanStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(PURCHASE_PLAN_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | purchasePlanMapper.auditPurchasePlan(id, ErpPurchasePlanStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (purchasePlanMapper.auditPurchasePlan(id, ErpPurchasePlanStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(PURCHASE_PLAN_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | // 6. 审核通过且未生成申请,自动生成采购申请 |
| | | if (!Boolean.TRUE.equals(plan.getGeneratedFlag())) { |
| | | try { |
| | |
| | | |
| | | private ErpPurchasePlanDO validatePurchasePlanCanModify(Long id) { |
| | | ErpPurchasePlanDO plan = validatePurchasePlanExists(id); |
| | | if (!ErpPurchasePlanStatusEnum.DRAFT.getStatus().equals(plan.getStatus())) { |
| | | if (!ErpPurchasePlanStatusEnum.DRAFT.getStatus().equals(plan.getStatus()) |
| | | && !ErpPurchasePlanStatusEnum.REJECT.getStatus().equals(plan.getStatus())) { |
| | | throw exception(PURCHASE_PLAN_UPDATE_FAIL_NOT_DRAFT, plan.getNo()); |
| | | } |
| | | return plan; |
| | |
| | | import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpPurchaseRequestMapper; |
| | | import cn.iocoder.yudao.module.erp.dal.mysql.purchase.ErpSupplierMapper; |
| | | import cn.iocoder.yudao.module.erp.dal.redis.no.ErpNoRedisDAO; |
| | | import cn.iocoder.yudao.module.erp.enums.ErpAuditStatus; |
| | | import cn.iocoder.yudao.module.erp.enums.ErpPurchaseOrderStatusEnum; |
| | | import cn.iocoder.yudao.module.erp.enums.ErpPurchaseRequestStatusEnum; |
| | | import cn.iocoder.yudao.module.mdm.api.item.MdmItemApi; |
| | | import cn.iocoder.yudao.module.mdm.api.item.dto.MdmItemRespDTO; |
| | |
| | | // 3. 校验审批配置已启用且配置了有效审批人 |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(PURCHASE_REQUEST_APPROVE_BIZ_TYPE); |
| | | // 4. 状态置为审批中,并清空上一轮审核结果 |
| | | purchaseRequestMapper.submitAndResetAuditInfo(id, ErpPurchaseRequestStatusEnum.PROCESS.getStatus()); |
| | | if (purchaseRequestMapper.submitAndResetAuditInfo(id, ErpPurchaseRequestStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(PURCHASE_REQUEST_SUBMIT_FAIL_NOT_ALLOWED); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(PURCHASE_REQUEST_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | purchaseRequestMapper.auditPurchaseRequest(id, ErpPurchaseRequestStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (purchaseRequestMapper.auditPurchaseRequest(id, ErpPurchaseRequestStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(PURCHASE_REQUEST_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见 |
| | | purchaseRequestMapper.auditPurchaseRequest(id, ErpPurchaseRequestStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (purchaseRequestMapper.auditPurchaseRequest(id, ErpPurchaseRequestStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(PURCHASE_REQUEST_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | // 6. 审核通过且有供应商、未生成订单时,自动生成采购订单 |
| | | if (purchaseRequest.getSupplierId() != null && purchaseRequest.getOrderId() == null) { |
| | | try { |
| | |
| | | // 3. 创建采购订单 |
| | | ErpPurchaseOrderDO purchaseOrder = new ErpPurchaseOrderDO(); |
| | | purchaseOrder.setNo(orderNo); |
| | | purchaseOrder.setStatus(ErpAuditStatus.APPROVE.getStatus()); // 采购订单直接为已审核状态 |
| | | // 自动生成的采购订单仍为草稿,必须走订单自身的提交/审批流程,避免绕过审批 |
| | | purchaseOrder.setStatus(ErpPurchaseOrderStatusEnum.DRAFT.getStatus()); |
| | | purchaseOrder.setSupplierId(purchaseRequest.getSupplierId()); |
| | | purchaseOrder.setOrderTime(purchaseRequest.getRequestTime()); |
| | | purchaseOrder.setTotalCount(purchaseRequest.getTotalCount()); |
| | |
| | | }); |
| | | purchaseOrderItemMapper.insertBatch(orderItems); |
| | | |
| | | // 5. 更新采购申请的订单信息 |
| | | // 5. 更新采购申请的订单信息,并回写最终使用的供应商 |
| | | purchaseRequestMapper.updateById(new ErpPurchaseRequestDO() |
| | | .setId(id) |
| | | .setSupplierId(purchaseRequest.getSupplierId()) |
| | | .setOrderId(purchaseOrder.getId()) |
| | | .setOrderNo(orderNo)); |
| | | |
| | |
| | | import cn.iocoder.yudao.module.erp.service.purchase.ErpPurchasePlanService; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | /** |
| | | * 采购计划审批状态监听器 |
| | | * 采购计划审批状态监听器(Legacy,已停用) |
| | | * |
| | | * 监听 BPM 流程实例状态变更事件,更新采购计划的审批状态 |
| | | * 采购计划审批已改为「审批配置」轻量级状态机,由 |
| | | * {@link ErpPurchasePlanService#submitPurchasePlan(Long)} / {@link ErpPurchasePlanService#auditPurchasePlan(Long, Boolean, String)} |
| | | * 直接驱动状态,不再依赖 BPM。 |
| | | * |
| | | * 保留本类仅作历史参考;不再注册为 Spring Bean,避免旧的 BPM 流程实例触发时 |
| | | * 与新审批路径重复更新/重复生成采购申请。 |
| | | * |
| | | * @author xiaoyi |
| | | */ |
| | | @Component |
| | | @Slf4j |
| | | public class ErpPurchasePlanStatusListener extends cn.iocoder.yudao.module.bpm.api.event.BpmProcessInstanceStatusEventListener { |
| | | |
| | |
| | | ErrorCode LEAVE_APPLICATION_DURATION_EXCEED = new ErrorCode(1_030_001_005, "请假时长超出年假余额"); |
| | | ErrorCode LEAVE_APPLICATION_AUDIT_FAIL_NOT_PROCESS = new ErrorCode(1_030_001_006, "只有审批中状态的请假申请才能审核"); |
| | | ErrorCode LEAVE_APPLICATION_AUDIT_REJECT_REASON_REQUIRED = new ErrorCode(1_030_001_007, "审核不通过时必须填写不通过原因"); |
| | | ErrorCode LEAVE_APPLICATION_APPLICANT_NOT_EXISTS = new ErrorCode(1_030_001_008, "请假申请人不存在"); |
| | | |
| | | // ========== 调岗申请 1-030-002-000 ========== |
| | | ErrorCode TRANSFER_APPLICATION_NOT_EXISTS = new ErrorCode(1_030_002_000, "调岗申请不存在"); |
| | |
| | | ErrorCode ATTENDANCE_RULE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_030_004_023, "导入考勤规则数据不能为空"); |
| | | ErrorCode ATTENDANCE_RULE_EXISTS = new ErrorCode(1_030_004_024, "已存在考勤规则【{}】,且未开启覆盖!"); |
| | | ErrorCode ATTENDANCE_RULE_DEPT_NOT_EXISTS = new ErrorCode(1_030_004_025, "部门【{}】不存在"); |
| | | ErrorCode ATTENDANCE_EXCEPTION_TIME_REQUIRED = new ErrorCode(1_030_004_026, "补卡申请必须填写补卡时间"); |
| | | |
| | | // ========== 绩效考核 1-030-008-000 ========== |
| | | ErrorCode PERFORMANCE_APPRAISE_NOT_EXISTS = new ErrorCode(1_030_008_000, "绩效考核方案不存在"); |
| | |
| | | ErrorCode PERFORMANCE_APPRAISE_SCOPE_TEAM_EMPTY = new ErrorCode(1_030_008_010, "指定班组为空,无法生成被考核人"); |
| | | ErrorCode PERFORMANCE_APPRAISE_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_030_008_011, "导入绩效考核方案数据不能为空"); |
| | | ErrorCode PERFORMANCE_APPRAISE_EXISTS = new ErrorCode(1_030_008_012, "已存在绩效考核方案【{}】,且未开启覆盖!"); |
| | | ErrorCode PERFORMANCE_APPRAISE_ITEM_WEIGHT_INVALID = new ErrorCode(1_030_008_013, "考核指标权重合计必须大于 0"); |
| | | |
| | | // ========== 薪酬管理 1-030-005-000 ========== |
| | | ErrorCode SALARY_STRUCTURE_NOT_EXISTS = new ErrorCode(1_030_005_000, "薪酬结构不存在"); |
| | |
| | | @NotNull(message = "异常日期不能为空") |
| | | private LocalDate exceptionDate; |
| | | |
| | | @Schema(description = "异常时间点", example = "2024-01-15 09:00:00") |
| | | @Schema(description = "异常时间点", requiredMode = Schema.RequiredMode.REQUIRED, example = "2024-01-15 09:00:00") |
| | | @NotNull(message = "异常时间点不能为空") |
| | | private LocalDateTime exceptionTime; |
| | | |
| | | @Schema(description = "申请原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "忘记打卡") |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<HrmLeaveApplicationDO>() |
| | | .eq(HrmLeaveApplicationDO::getId, id) |
| | | .in(HrmLeaveApplicationDO::getStatus, |
| | | HrmAuditStatusEnum.DRAFT.getStatus(), HrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(HrmLeaveApplicationDO::getStatus, status) |
| | | .set(HrmLeaveApplicationDO::getReviewerId, null) |
| | | .set(HrmLeaveApplicationDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<HrmLeaveApplicationDO>() |
| | | .eq(HrmLeaveApplicationDO::getId, id) |
| | | .eq(HrmLeaveApplicationDO::getStatus, HrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(HrmLeaveApplicationDO::getStatus, status) |
| | | .set(HrmLeaveApplicationDO::getReviewerId, reviewerId) |
| | | .set(HrmLeaveApplicationDO::getReviewerName, reviewerName) |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmRegularizeApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmRegularizeApplicationDO; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<HrmRegularizeApplicationDO>() |
| | | .eq(HrmRegularizeApplicationDO::getId, id) |
| | | .in(HrmRegularizeApplicationDO::getStatus, |
| | | HrmAuditStatusEnum.DRAFT.getStatus(), HrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(HrmRegularizeApplicationDO::getStatus, status) |
| | | .set(HrmRegularizeApplicationDO::getReviewerId, null) |
| | | .set(HrmRegularizeApplicationDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<HrmRegularizeApplicationDO>() |
| | | .eq(HrmRegularizeApplicationDO::getId, id) |
| | | .eq(HrmRegularizeApplicationDO::getStatus, HrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(HrmRegularizeApplicationDO::getStatus, status) |
| | | .set(HrmRegularizeApplicationDO::getReviewerId, reviewerId) |
| | | .set(HrmRegularizeApplicationDO::getReviewerName, reviewerName) |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmResignationApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmResignationApplicationDO; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<HrmResignationApplicationDO>() |
| | | .eq(HrmResignationApplicationDO::getId, id) |
| | | .in(HrmResignationApplicationDO::getStatus, |
| | | HrmAuditStatusEnum.DRAFT.getStatus(), HrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(HrmResignationApplicationDO::getStatus, status) |
| | | .set(HrmResignationApplicationDO::getReviewerId, null) |
| | | .set(HrmResignationApplicationDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<HrmResignationApplicationDO>() |
| | | .eq(HrmResignationApplicationDO::getId, id) |
| | | .eq(HrmResignationApplicationDO::getStatus, HrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(HrmResignationApplicationDO::getStatus, status) |
| | | .set(HrmResignationApplicationDO::getReviewerId, reviewerId) |
| | | .set(HrmResignationApplicationDO::getReviewerName, reviewerName) |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.approval.vo.HrmTransferApplicationPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.approval.HrmTransferApplicationDO; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<HrmTransferApplicationDO>() |
| | | .eq(HrmTransferApplicationDO::getId, id) |
| | | .in(HrmTransferApplicationDO::getStatus, |
| | | HrmAuditStatusEnum.DRAFT.getStatus(), HrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(HrmTransferApplicationDO::getStatus, status) |
| | | .set(HrmTransferApplicationDO::getReviewerId, null) |
| | | .set(HrmTransferApplicationDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<HrmTransferApplicationDO>() |
| | | .eq(HrmTransferApplicationDO::getId, id) |
| | | .eq(HrmTransferApplicationDO::getStatus, HrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(HrmTransferApplicationDO::getStatus, status) |
| | | .set(HrmTransferApplicationDO::getReviewerId, reviewerId) |
| | | .set(HrmTransferApplicationDO::getReviewerName, reviewerName) |
| | | .set(HrmTransferApplicationDO::getReviewTime, LocalDateTime.now()) |
| | | .set(HrmTransferApplicationDO::getReviewRemark, reviewRemark) |
| | | .set(HrmTransferApplicationDO::getApproveTime, LocalDateTime.now())); |
| | | // 仅审核通过时写入通过时间,驳回不写 |
| | | .set(HrmAuditStatusEnum.APPROVE.getStatus().equals(status), |
| | | HrmTransferApplicationDO::getApproveTime, LocalDateTime.now())); |
| | | } |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.attendance.vo.HrmAttendanceExceptionPageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.attendance.HrmAttendanceExceptionDO; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer status) { |
| | | return update(null, new LambdaUpdateWrapper<HrmAttendanceExceptionDO>() |
| | | .eq(HrmAttendanceExceptionDO::getId, id) |
| | | .in(HrmAttendanceExceptionDO::getStatus, |
| | | HrmAuditStatusEnum.DRAFT.getStatus(), HrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(HrmAttendanceExceptionDO::getStatus, status) |
| | | .set(HrmAttendanceExceptionDO::getReviewerId, null) |
| | | .set(HrmAttendanceExceptionDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<HrmAttendanceExceptionDO>() |
| | | .eq(HrmAttendanceExceptionDO::getId, id) |
| | | .eq(HrmAttendanceExceptionDO::getStatus, HrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(HrmAttendanceExceptionDO::getStatus, status) |
| | | .set(HrmAttendanceExceptionDO::getReviewerId, reviewerId) |
| | | .set(HrmAttendanceExceptionDO::getReviewerName, reviewerName) |
| | | .set(HrmAttendanceExceptionDO::getReviewTime, LocalDateTime.now()) |
| | | .set(HrmAttendanceExceptionDO::getReviewRemark, reviewRemark) |
| | | .set(HrmAttendanceExceptionDO::getApproveTime, LocalDateTime.now())); |
| | | // 仅审核通过时写入通过时间,驳回不写 |
| | | .set(HrmAuditStatusEnum.APPROVE.getStatus().equals(status), |
| | | HrmAttendanceExceptionDO::getApproveTime, LocalDateTime.now())); |
| | | } |
| | | |
| | | } |
| | |
| | | import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; |
| | | import cn.iocoder.yudao.module.hrm.controller.admin.performanceappraise.vo.HrmPerformanceAppraisePageReqVO; |
| | | import cn.iocoder.yudao.module.hrm.dal.dataobject.performanceappraise.HrmPerformanceAppraiseDO; |
| | | import cn.iocoder.yudao.module.hrm.enums.HrmAuditStatusEnum; |
| | | import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; |
| | | import org.apache.ibatis.annotations.Mapper; |
| | | |
| | |
| | | default int submitAndResetAuditInfo(Long id, Integer auditStatus) { |
| | | return update(null, new LambdaUpdateWrapper<HrmPerformanceAppraiseDO>() |
| | | .eq(HrmPerformanceAppraiseDO::getId, id) |
| | | .in(HrmPerformanceAppraiseDO::getAuditStatus, |
| | | HrmAuditStatusEnum.DRAFT.getStatus(), HrmAuditStatusEnum.REJECT.getStatus()) |
| | | .set(HrmPerformanceAppraiseDO::getAuditStatus, auditStatus) |
| | | .set(HrmPerformanceAppraiseDO::getReviewerId, null) |
| | | .set(HrmPerformanceAppraiseDO::getReviewerName, null) |
| | |
| | | String reviewerName, String reviewRemark) { |
| | | return update(null, new LambdaUpdateWrapper<HrmPerformanceAppraiseDO>() |
| | | .eq(HrmPerformanceAppraiseDO::getId, id) |
| | | .eq(HrmPerformanceAppraiseDO::getAuditStatus, HrmAuditStatusEnum.PROCESS.getStatus()) |
| | | .set(HrmPerformanceAppraiseDO::getAuditStatus, auditStatus) |
| | | .set(HrmPerformanceAppraiseDO::getStatus, status) |
| | | .set(HrmPerformanceAppraiseDO::getReviewerId, reviewerId) |
| | |
| | | } |
| | | AdminUserRespDTO user = adminUserApi.getUser(userId); |
| | | if (user == null) { |
| | | userId = getCurrentUserId(); |
| | | throw exception(LEAVE_APPLICATION_APPLICANT_NOT_EXISTS); |
| | | } |
| | | // 3. 插入 |
| | | HrmLeaveApplicationDO application = BeanUtils.toBean(createReqVO, HrmLeaveApplicationDO.class); |
| | |
| | | public void updateLeaveApplication(HrmLeaveApplicationSaveReqVO updateReqVO) { |
| | | // 校验存在 |
| | | HrmLeaveApplicationDO application = validateLeaveApplicationExists(updateReqVO.getId()); |
| | | // 校验状态为草稿或审批中 |
| | | // 校验状态为草稿或审核不通过(审批中禁止修改) |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && !Objects.equals(application.getStatus(), HrmAuditStatusEnum.PROCESS.getStatus())) { |
| | | && !Objects.equals(application.getStatus(), HrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(LEAVE_APPLICATION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | // 更新 |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(LEAVE_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | leaveApplicationMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()); |
| | | if (leaveApplicationMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(LEAVE_APPLICATION_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(LEAVE_APPLICATION_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | leaveApplicationMapper.auditLeaveApplication(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (leaveApplicationMapper.auditLeaveApplication(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(LEAVE_APPLICATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | leaveApplicationMapper.auditLeaveApplication(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (leaveApplicationMapper.auditLeaveApplication(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(LEAVE_APPLICATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | @Override |
| | | public void updateRegularizeApplication(HrmRegularizeApplicationSaveReqVO updateReqVO) { |
| | | HrmRegularizeApplicationDO application = validateRegularizeApplicationExists(updateReqVO.getId()); |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus())) { |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && !Objects.equals(application.getStatus(), HrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(REGULARIZE_APPLICATION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | HrmRegularizeApplicationDO updateObj = BeanUtils.toBean(updateReqVO, HrmRegularizeApplicationDO.class); |
| | |
| | | @Override |
| | | public void deleteRegularizeApplication(Long id) { |
| | | HrmRegularizeApplicationDO application = validateRegularizeApplicationExists(id); |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus())) { |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && !Objects.equals(application.getStatus(), HrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(REGULARIZE_APPLICATION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | regularizeApplicationMapper.deleteById(id); |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(REGULARIZE_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | regularizeApplicationMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()); |
| | | if (regularizeApplicationMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(REGULARIZE_APPLICATION_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(REGULARIZE_APPLICATION_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | regularizeApplicationMapper.auditRegularizeApplication(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (regularizeApplicationMapper.auditRegularizeApplication(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(REGULARIZE_APPLICATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | regularizeApplicationMapper.auditRegularizeApplication(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (regularizeApplicationMapper.auditRegularizeApplication(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(REGULARIZE_APPLICATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | |
| | | // 6. 审核通过后置业务逻辑:回写员工主档(状态=在职,用工性质=正式,转正日期 = 拟转正日期或当天) |
| | | writeBackEmployee(application); |
| | |
| | | @Override |
| | | public void updateResignationApplication(HrmResignationApplicationSaveReqVO updateReqVO) { |
| | | HrmResignationApplicationDO application = validateResignationApplicationExists(updateReqVO.getId()); |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus())) { |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && !Objects.equals(application.getStatus(), HrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(RESIGNATION_APPLICATION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | HrmResignationApplicationDO updateObj = BeanUtils.toBean(updateReqVO, HrmResignationApplicationDO.class); |
| | |
| | | @Override |
| | | public void deleteResignationApplication(Long id) { |
| | | HrmResignationApplicationDO application = validateResignationApplicationExists(id); |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus())) { |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && !Objects.equals(application.getStatus(), HrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(RESIGNATION_APPLICATION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | storageAttachmentApi.deleteAttachmentsByRecord("hrm_resignation_application", id); |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(RESIGNATION_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | resignationApplicationMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()); |
| | | if (resignationApplicationMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(RESIGNATION_APPLICATION_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(RESIGNATION_APPLICATION_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | resignationApplicationMapper.auditResignationApplication(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (resignationApplicationMapper.auditResignationApplication(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(RESIGNATION_APPLICATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | resignationApplicationMapper.auditResignationApplication(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (resignationApplicationMapper.auditResignationApplication(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(RESIGNATION_APPLICATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | |
| | | // 6. 审核通过后置业务逻辑:回写员工主档(状态=离职,离职日期 = 实际离职日期或预计离职日期) |
| | | writeBackEmployee(application); |
| | |
| | | public void updateTransferApplication(HrmTransferApplicationSaveReqVO updateReqVO) { |
| | | HrmTransferApplicationDO application = validateTransferApplicationExists(updateReqVO.getId()); |
| | | if (!Objects.equals(application.getStatus(), HrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && !Objects.equals(application.getStatus(), HrmAuditStatusEnum.PROCESS.getStatus())) { |
| | | && !Objects.equals(application.getStatus(), HrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(TRANSFER_APPLICATION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | if (Objects.equals(updateReqVO.getTargetDeptId(), updateReqVO.getCurrentDeptId())) { |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(TRANSFER_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | transferApplicationMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()); |
| | | if (transferApplicationMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(TRANSFER_APPLICATION_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(TRANSFER_APPLICATION_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | transferApplicationMapper.auditTransferApplication(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (transferApplicationMapper.auditTransferApplication(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(TRANSFER_APPLICATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | transferApplicationMapper.auditTransferApplication(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (transferApplicationMapper.auditTransferApplication(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(TRANSFER_APPLICATION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | |
| | | // 6. 审核通过后置业务逻辑:回写员工主档(部门 = 目标部门,岗位 = 目标岗位) |
| | | writeBackEmployee(application); |
| | |
| | | @Override |
| | | public void updateAttendanceException(HrmAttendanceExceptionSaveReqVO updateReqVO) { |
| | | HrmAttendanceExceptionDO attendanceException = validateAttendanceExceptionExists(updateReqVO.getId()); |
| | | if (!HrmAuditStatusEnum.DRAFT.getStatus().equals(attendanceException.getStatus())) { |
| | | if (!HrmAuditStatusEnum.DRAFT.getStatus().equals(attendanceException.getStatus()) |
| | | && !HrmAuditStatusEnum.REJECT.getStatus().equals(attendanceException.getStatus())) { |
| | | throw exception(ATTENDANCE_EXCEPTION_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | HrmAttendanceExceptionDO updateObj = BeanUtils.toBean(updateReqVO, HrmAttendanceExceptionDO.class); |
| | |
| | | @Override |
| | | public void deleteAttendanceException(Long id) { |
| | | HrmAttendanceExceptionDO attendanceException = validateAttendanceExceptionExists(id); |
| | | if (!HrmAuditStatusEnum.DRAFT.getStatus().equals(attendanceException.getStatus())) { |
| | | if (!HrmAuditStatusEnum.DRAFT.getStatus().equals(attendanceException.getStatus()) |
| | | && !HrmAuditStatusEnum.REJECT.getStatus().equals(attendanceException.getStatus())) { |
| | | throw exception(ATTENDANCE_EXCEPTION_DELETE_FAIL_NOT_DRAFT); |
| | | } |
| | | storageAttachmentApi.deleteAttachmentsByRecord("hrm_attendance_exception", id); |
| | |
| | | throw exception(ATTENDANCE_EXCEPTION_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | |
| | | // 2. 校验审批配置已启用且配置了有效审批人(未配置时抛出带明确提示的业务异常) |
| | | // 2. 补卡类型必须填写补卡时间,避免审核通过后回填考勤记录时出现空指针 |
| | | if (HrmAttendanceExceptionTypeEnum.SUPPLEMENT.getType().equals(exception.getType()) |
| | | && exception.getExceptionTime() == null) { |
| | | throw exception(ATTENDANCE_EXCEPTION_TIME_REQUIRED); |
| | | } |
| | | |
| | | // 3. 校验审批配置已启用且配置了有效审批人(未配置时抛出带明确提示的业务异常) |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(ATTENDANCE_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | attendanceExceptionMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()); |
| | | // 4. 状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | if (attendanceExceptionMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(ATTENDANCE_EXCEPTION_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (!HrmAuditStatusEnum.PROCESS.getStatus().equals(exception.getStatus())) { |
| | | throw exception(ATTENDANCE_EXCEPTION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | // 2.1 补卡类型必须填写补卡时间,避免审核通过后回填考勤记录时出现空指针 |
| | | if (HrmAttendanceExceptionTypeEnum.SUPPLEMENT.getType().equals(exception.getType()) |
| | | && exception.getExceptionTime() == null) { |
| | | throw exception(ATTENDANCE_EXCEPTION_TIME_REQUIRED); |
| | | } |
| | | // 3. 校验当前登录用户是该业务类型的审批人(或签:任一人均可审核) |
| | | Long userId = getLoginUserId(); |
| | | approvalConfigApi.validateApprover(ATTENDANCE_APPROVE_BIZ_TYPE, userId); |
| | |
| | | if (StrUtil.isBlank(reviewRemark)) { |
| | | throw exception(ATTENDANCE_EXCEPTION_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | attendanceExceptionMapper.auditAttendanceException(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (attendanceExceptionMapper.auditAttendanceException(id, HrmAuditStatusEnum.REJECT.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ATTENDANCE_EXCEPTION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,状态置为审核通过 |
| | | attendanceExceptionMapper.auditAttendanceException(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (attendanceExceptionMapper.auditAttendanceException(id, HrmAuditStatusEnum.APPROVE.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ATTENDANCE_EXCEPTION_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | |
| | | // 6. 审核通过后置业务逻辑:补卡回填上下班时间 / 加班回写加班时长 |
| | | if (HrmAttendanceExceptionTypeEnum.SUPPLEMENT.getType().equals(exception.getType())) { |
| | |
| | | import cn.iocoder.yudao.module.system.api.dept.DeptApi; |
| | | import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; |
| | | import jakarta.annotation.Resource; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | |
| | | */ |
| | | @Service |
| | | @Validated |
| | | @Slf4j |
| | | public class HrmAttendanceRecordServiceImpl implements HrmAttendanceRecordService { |
| | | |
| | | @Resource |
| | |
| | | } |
| | | LocalDate exceptionDate = exception.getExceptionDate(); |
| | | LocalDateTime exceptionTime = exception.getExceptionTime(); |
| | | // 补卡时间缺失时无法回填考勤记录,记录日志并跳过,避免空指针 |
| | | if (exceptionTime == null) { |
| | | log.warn("[supplementClockIn] 补卡申请({}) 补卡时间为空,跳过考勤记录回填", exception.getId()); |
| | | return; |
| | | } |
| | | Long userId = exception.getUserId(); |
| | | HrmEmployeeDO employee = employeeService.getEmployee(userId); |
| | | HrmAttendanceRuleDO rule = employee == null ? null |
| | |
| | | approvalConfigApi.validateApprovalEnabledAndGetApprovers(APPRAISE_APPROVE_BIZ_TYPE); |
| | | |
| | | // 3. 审批状态置为审批中,并清空上一轮审核结果,避免残留「审核不通过」的原因 |
| | | appraiseMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()); |
| | | if (appraiseMapper.submitAndResetAuditInfo(id, HrmAuditStatusEnum.PROCESS.getStatus()) != 1) { |
| | | throw exception(ErrorCodeConstants.PERFORMANCE_APPRAISE_SUBMIT_FAIL_NOT_EDITABLE); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | throw exception(ErrorCodeConstants.PERFORMANCE_APPRAISE_AUDIT_REJECT_REASON_REQUIRED); |
| | | } |
| | | // 方案状态保持不变 |
| | | appraiseMapper.auditAppraise(id, HrmAuditStatusEnum.REJECT.getStatus(), appraise.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (appraiseMapper.auditAppraise(id, HrmAuditStatusEnum.REJECT.getStatus(), appraise.getStatus(), |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ErrorCodeConstants.PERFORMANCE_APPRAISE_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | return; |
| | | } |
| | | // 5. 审核通过:记录审核人与审核意见,审批状态置为审核通过 |
| | | // 6. 审核通过后置业务逻辑:方案状态流转为「已发布」 |
| | | appraiseMapper.auditAppraise(id, HrmAuditStatusEnum.APPROVE.getStatus(), STATUS_PUBLISHED, |
| | | userId, getUserNickname(userId), reviewRemark); |
| | | if (appraiseMapper.auditAppraise(id, HrmAuditStatusEnum.APPROVE.getStatus(), STATUS_PUBLISHED, |
| | | userId, getUserNickname(userId), reviewRemark) != 1) { |
| | | throw exception(ErrorCodeConstants.PERFORMANCE_APPRAISE_AUDIT_FAIL_NOT_PROCESS); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | .setWeight(weight) |
| | | .setSelfScore(selfScore) |
| | | .setSuperiorScore(superiorScore)); |
| | | } |
| | | // 权重合计为 0 时无法计算加权得分,避免除零 |
| | | if (sumWeight.compareTo(BigDecimal.ZERO) <= 0) { |
| | | throw exception(ErrorCodeConstants.PERFORMANCE_APPRAISE_ITEM_WEIGHT_INVALID); |
| | | } |
| | | BigDecimal selfTotal = weightedSelf.divide(sumWeight, 1, RoundingMode.HALF_UP); |
| | | BigDecimal superiorTotal = weightedSuperior.divide(sumWeight, 1, RoundingMode.HALF_UP); |
| | |
| | | |
| | | private HrmPerformanceAppraiseDO validateAppraiseCanModify(Long id) { |
| | | HrmPerformanceAppraiseDO appraise = validateAppraiseExists(id); |
| | | if (ObjUtil.notEqual(appraise.getStatus(), STATUS_DRAFT)) { |
| | | // 以审批状态为准:仅草稿 / 审核不通过允许修改,审批中禁止修改 |
| | | if (ObjUtil.notEqual(appraise.getAuditStatus(), HrmAuditStatusEnum.DRAFT.getStatus()) |
| | | && ObjUtil.notEqual(appraise.getAuditStatus(), HrmAuditStatusEnum.REJECT.getStatus())) { |
| | | throw exception(ErrorCodeConstants.PERFORMANCE_APPRAISE_UPDATE_FAIL_NOT_DRAFT); |
| | | } |
| | | return appraise; |
| | |
| | | @Schema(description = "编号", requiredMode = Schema.RequiredMode.NOT_REQUIRED, example = "1024") |
| | | private Long id; |
| | | |
| | | @Schema(description = "模板编码(留空则自动生成)", example = "PPT000001") |
| | | private String templateCode; |
| | | |
| | | @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "注塑工艺参数模板") |
| | | @NotBlank(message = "模板名称不能为空") |
| | | private String templateName; |
| | |
| | | package cn.iocoder.yudao.module.mes.controller.admin.pd.techconfirm.vo; |
| | | |
| | | import io.swagger.v3.oas.annotations.media.Schema; |
| | | import jakarta.validation.constraints.NotBlank; |
| | | import lombok.Data; |
| | | |
| | | /** |
| | |
| | | private Long id; |
| | | |
| | | @Schema(description = "确认函编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "TC20260801001") |
| | | @NotBlank(message = "确认函编号不能为空") |
| | | private String confirmNo; |
| | | |
| | | @Schema(description = "客户ID(关联 crm_customer.id)", example = "2048") |
| | |
| | | ErrorCode PRO_FEEDBACK_UNCHECK_QUANTITY_EXISTS = new ErrorCode(1_040_506_012, "当前报工单未完成检验(待检数量:{}),无法执行报工"); |
| | | ErrorCode PRO_FEEDBACK_BACKFLUSH_BOM_REQUIRED = new ErrorCode(1_040_506_013, "当前工序为倒冲工序,但未配置BOM消耗,无法报工"); |
| | | ErrorCode PRO_FEEDBACK_CANNOT_CREATE_WHEN_PAUSED = new ErrorCode(1_040_506_014, "生产任务处于停工状态,无法报工"); |
| | | ErrorCode PRO_FEEDBACK_APPROVER_NOT_CONFIGURED = new ErrorCode(1_040_506_015, "报工单未指定审核人,无法审批"); |
| | | ErrorCode PRO_FEEDBACK_NOT_APPROVER = new ErrorCode(1_040_506_016, "您不是该报工单的指定审核人,无权审批"); |
| | | |
| | | // ========== MES 生产管理-生产流转卡(1-040-507-000) ========== |
| | | ErrorCode PRO_CARD_NOT_EXISTS = new ErrorCode(1_040_507_000, "生产流转卡不存在"); |
| | |
| | | ErrorCode WM_STOCK_TAKING_TASK_ALREADY_SUBMIT_APPROVAL = new ErrorCode(1_040_714_123, "盘点结果审批已提交,请勿重复提交"); |
| | | ErrorCode WM_STOCK_TAKING_TASK_RESULT_NOT_SUBMITTED = new ErrorCode(1_040_714_124, "只有已提交结果审批的盘点任务才能审核"); |
| | | ErrorCode WM_STOCK_TAKING_TASK_REJECT_REASON_REQUIRED = new ErrorCode(1_040_714_125, "审核不通过时必须填写不通过原因"); |
| | | ErrorCode WM_STOCK_TAKING_TASK_RESULT_APPROVAL_PENDING = new ErrorCode(1_040_714_126, "盘点结果审批已提交,审核完成前不允许修改盘点结果"); |
| | | ErrorCode WM_STOCK_TAKING_TASK_LINE_NOT_MATCH = new ErrorCode(1_040_714_127, "盘点任务行不属于指定的盘点任务"); |
| | | |
| | | // ========== MES 仓库管理-销售出库单(1-040-714-000) ========== |
| | | ErrorCode WM_PRODUCT_SALES_NOT_EXISTS = new ErrorCode(1_040_714_000, "销售出库单不存在"); |
| | |
| | | ErrorCode WM_MISC_ISSUE_REJECT_REASON_REQUIRED = new ErrorCode(1_040_715_007, "审核不通过时必须填写不通过原因"); |
| | | ErrorCode WM_MISC_ISSUE_LINE_NOT_EXISTS = new ErrorCode(1_040_715_100, "杂项出库单行不存在"); |
| | | ErrorCode WM_MISC_ISSUE_DETAIL_NOT_EXISTS = new ErrorCode(1_040_715_200, "杂项出库单明细不存在"); |
| | | ErrorCode WM_MISC_ISSUE_QUANTITY_INVALID = new ErrorCode(1_040_715_008, "杂项出库数量不能为空"); |
| | | |
| | | // ========== MES 仓库管理-杂项入库单(1-040-716-000) ========== |
| | | ErrorCode WM_MISC_RECEIPT_NOT_EXISTS = new ErrorCode(1_040_716_000, "杂项入库单不存在"); |
| | |
| | | ErrorCode PD_PROJECT_NOT_APPROVING = new ErrorCode(1_040_800_009, "只有审批中状态的设计项目才能审核"); |
| | | ErrorCode PD_PROJECT_AUDIT_REJECT_REASON_REQUIRED = new ErrorCode(1_040_800_010, "审核不通过时必须填写不通过原因"); |
| | | ErrorCode PD_PROJECT_IMPORT_LIST_IS_EMPTY = new ErrorCode(1_040_800_011, "导入设计项目数据不能为空"); |
| | | ErrorCode PD_PROJECT_NO_DOCUMENT = new ErrorCode(1_040_800_012, "设计项目至少需要一份资料才允许提交审批"); |
| | | |
| | | // ========== MES 产品设计-资料子表(1-040-801-000) ========== |
| | | ErrorCode PD_DOCUMENT_NOT_EXISTS = new ErrorCode(1_040_801_000, "设计资料不存在"); |
| | |
| | | ErrorCode PD_TECH_CONFIRM_NOT_PENDING_AUDIT = new ErrorCode(1_040_808_004, "只有待审核状态的技术确认函才能审核"); |
| | | ErrorCode PD_TECH_CONFIRM_REJECT_REASON_REQUIRED = new ErrorCode(1_040_808_007, "审核不通过时必须填写不通过原因"); |
| | | ErrorCode PD_TECH_CONFIRM_NOT_AUDITED_FOR_CUSTOMER_CONFIRM = new ErrorCode(1_040_808_008, "只有已审核状态的技术确认函才能进行客户确认"); |
| | | ErrorCode PD_TECH_CONFIRM_NO_REQUIRED = new ErrorCode(1_040_808_009, "确认函编号不能为空"); |
| | | |
| | | // ========== MES 产品设计-产品档案与基础数据(1-040-809-000) ========== |
| | | ErrorCode PD_PRODUCT_NOT_EXISTS = new ErrorCode(1_040_809_000, "产品档案不存在"); |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createProcessParamTemplate(MesPdProcessParamTemplateSaveReqVO createReqVO) { |
| | | // 1. 生成模板编码 |
| | | String templateCode = autoCodeRecordService.generateAutoCode( |
| | | MesMdAutoCodeRuleCodeEnum.PD_PROCESS_PARAM_TEMPLATE_CODE.getCode()); |
| | | // 1. 使用手填编码,或自动生成编码 |
| | | String templateCode = createReqVO.getTemplateCode(); |
| | | if (StrUtil.isNotBlank(templateCode)) { |
| | | if (templateMapper.selectByTemplateCode(templateCode) != null) { |
| | | throw exception(PD_PROCESS_PARAM_TEMPLATE_CODE_DUPLICATE); |
| | | } |
| | | } else { |
| | | templateCode = autoCodeRecordService.generateAutoCode( |
| | | MesMdAutoCodeRuleCodeEnum.PD_PROCESS_PARAM_TEMPLATE_CODE.getCode()); |
| | | } |
| | | // 2. 插入模板主表 |
| | | MesPdProcessParamTemplateDO template = BeanUtils.toBean(createReqVO, MesPdProcessParamTemplateDO.class); |
| | | template.setTemplateCode(templateCode); |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateProcessParamTemplate(MesPdProcessParamTemplateSaveReqVO updateReqVO) { |
| | | // 1. 校验存在 |
| | | validateProcessParamTemplateExists(updateReqVO.getId()); |
| | | // 2. 更新模板主表 |
| | | MesPdProcessParamTemplateDO existing = validateProcessParamTemplateExists(updateReqVO.getId()); |
| | | // 2. 更新模板主表:编码留空或未变化则不修改;填写了新编码则校验唯一 |
| | | MesPdProcessParamTemplateDO updateObj = BeanUtils.toBean(updateReqVO, MesPdProcessParamTemplateDO.class); |
| | | String templateCode = updateReqVO.getTemplateCode(); |
| | | if (StrUtil.isNotBlank(templateCode) && !StrUtil.equals(templateCode, existing.getTemplateCode())) { |
| | | if (templateMapper.selectByTemplateCode(templateCode) != null) { |
| | | throw exception(PD_PROCESS_PARAM_TEMPLATE_CODE_DUPLICATE); |
| | | } |
| | | updateObj.setTemplateCode(templateCode); |
| | | } else { |
| | | // 置空,避免 MyBatis-Plus 更新时覆盖原编码 |
| | | updateObj.setTemplateCode(null); |
| | | } |
| | | templateMapper.updateById(updateObj); |
| | | // 3. 删除旧明细并重新插入(快照模式:先删后插) |
| | | detailMapper.deleteByTemplateId(updateReqVO.getId()); |
| | |
| | | } |
| | | // 2. 校验该项目下所有资料审核记录均已审核(不存在待审核的记录) |
| | | List<MesPdDocumentDO> documents = documentService.getDocumentListByProjectId(id); |
| | | if (CollUtil.isEmpty(documents)) { |
| | | throw exception(PD_PROJECT_NO_DOCUMENT); |
| | | } |
| | | List<Long> documentIds = documents.stream().map(MesPdDocumentDO::getId).toList(); |
| | | if (documentAuditMapper.existsPendingAuditByDocumentIds(documentIds)) { |
| | | throw exception(PD_PROJECT_AUDIT_NOT_FINISHED); |
| | |
| | | } |
| | | |
| | | private void validateConfirmNoUnique(String confirmNo, Long excludeId) { |
| | | if (confirmNo == null) { |
| | | return; |
| | | // 确认函编号必填:VO 上的 @NotBlank 只覆盖接口入参,Service 内(含导入)仍需显式校验 |
| | | if (StrUtil.isBlank(confirmNo)) { |
| | | throw exception(PD_TECH_CONFIRM_NO_REQUIRED); |
| | | } |
| | | ProductTechConfirmDO techConfirm = techConfirmMapper.selectOne( |
| | | ProductTechConfirmDO::getConfirmNo, confirmNo); |
| | |
| | | @Override |
| | | public void rejectFeedback(Long id) { |
| | | // 1. 校验存在 + 审批中状态 |
| | | validateFeedbackStatusApproving(id); |
| | | MesProFeedbackDO feedback = validateFeedbackStatusApproving(id); |
| | | // 1.1 校验当前登录人是该报工单的指定审核人 |
| | | validateCurrentUserIsApprover(feedback); |
| | | |
| | | // 2. 更新状态为草稿 |
| | | feedbackMapper.updateById(new MesProFeedbackDO().setId(id) |
| | |
| | | public boolean approveFeedback(MesProFeedbackApproveReqVO reqVO) { |
| | | // 1.1 校验存在 + 审批中状态 |
| | | MesProFeedbackDO feedback = validateFeedbackStatusApproving(reqVO.getId()); |
| | | // 1.1.1 校验当前登录人是该报工单的指定审核人 |
| | | validateCurrentUserIsApprover(feedback); |
| | | // 1.2 校验报工数量 > 0 |
| | | if (feedback.getFeedbackQuantity() == null |
| | | || feedback.getFeedbackQuantity().compareTo(BigDecimal.ZERO) <= 0) { |
| | |
| | | } |
| | | |
| | | /** |
| | | * 校验当前登录用户是否为报工单指定的审核人 |
| | | * |
| | | * 报工单创建时必须指定 approveUserId,审批通过/驳回只能由该审核人操作, |
| | | * 避免任意拥有菜单权限的用户越权审批。 |
| | | * |
| | | * @param feedback 报工单 |
| | | */ |
| | | private void validateCurrentUserIsApprover(MesProFeedbackDO feedback) { |
| | | if (feedback.getApproveUserId() == null) { |
| | | throw exception(PRO_FEEDBACK_APPROVER_NOT_CONFIGURED); |
| | | } |
| | | if (!feedback.getApproveUserId().equals(getLoginUserId())) { |
| | | throw exception(PRO_FEEDBACK_NOT_APPROVER); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 校验报工单的业务数据(创建 & 修改共用) |
| | | * |
| | | * <p>以生产任务为核心:前端只需传 taskId,workOrderId、routeId、processId、itemId、workstationId |
| | |
| | | void submitItemReceipt(Long id); |
| | | |
| | | /** |
| | | * 执行上架(待上架 → 待入库) |
| | | * 执行上架校验(仅校验已审批单据的明细数量一致性,不修改单据状态) |
| | | * |
| | | * 单据状态只能由审核(APPROVING → APPROVED)与入库(APPROVED → FINISHED)推进, |
| | | * 本方法不得把单据直接置为已审批。 |
| | | * |
| | | * @param id 编号 |
| | | */ |
| | |
| | | void cancelItemReceipt(Long id); |
| | | |
| | | /** |
| | | * 校验采购入库单存在且处于可编辑状态(草稿或待上架) |
| | | * 校验采购入库单存在且处于可编辑状态(仅草稿) |
| | | * |
| | | * @param id 编号 |
| | | * @return 采购入库单 |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void stockItemReceipt(Long id) { |
| | | // 校验存在 |
| | | // 校验存在 + 已审批(状态只能由 audit 推进:APPROVING → APPROVED) |
| | | MesWmItemReceiptDO receipt = validateItemReceiptExists(id); |
| | | if (ObjUtil.notEqual(MesWmItemReceiptStatusEnum.APPROVING.getStatus(), receipt.getStatus())) { |
| | | if (ObjUtil.notEqual(MesWmItemReceiptStatusEnum.APPROVED.getStatus(), receipt.getStatus())) { |
| | | throw exception(WM_ITEM_RECEIPT_STATUS_ERROR); |
| | | } |
| | | // 校验每行明细数量之和是否等于行入库数量 |
| | |
| | | throw exception(WM_ITEM_RECEIPT_DETAIL_QUANTITY_MISMATCH); |
| | | } |
| | | } |
| | | |
| | | // 执行上架(待上架 → 待入库) |
| | | itemReceiptMapper.updateById(new MesWmItemReceiptDO() |
| | | .setId(id).setStatus(MesWmItemReceiptStatusEnum.APPROVED.getStatus())); |
| | | // 注意:本方法仅做数量一致性校验,不得修改单据状态。 |
| | | // 状态流转由 audit(APPROVING → APPROVED)与 finish(APPROVED → FINISHED)负责。 |
| | | } |
| | | |
| | | @Override |
| | |
| | | |
| | | @Override |
| | | public MesWmItemReceiptDO validateItemReceiptEditable(Long id) { |
| | | MesWmItemReceiptDO receipt = validateItemReceiptExists(id); |
| | | if (ObjUtil.notEqual(receipt.getStatus(), MesWmItemReceiptStatusEnum.PREPARE.getStatus()) |
| | | && ObjUtil.notEqual(receipt.getStatus(), MesWmItemReceiptStatusEnum.APPROVING.getStatus())) { |
| | | throw exception(WM_ITEM_RECEIPT_STATUS_NOT_PREPARE); |
| | | } |
| | | return receipt; |
| | | // 仅草稿状态允许编辑行/明细;审批中(APPROVING)已锁定,避免绕过审核修改数据 |
| | | return validateItemReceiptExistsAndDraft(id); |
| | | } |
| | | |
| | | private MesWmItemReceiptDO validateItemReceiptExists(Long id) { |
| | |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.validation.annotation.Validated; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.util.ArrayList; |
| | | import java.util.LinkedHashMap; |
| | | import java.util.List; |
| | |
| | | List<MesWmMiscIssueLineDO> lines = miscIssueLineService.getMiscIssueLineListByIssueId(issue.getId()); |
| | | wmTransactionService.createTransactionList(convertList(lines, line -> new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.OUT.getType()).setItemId(line.getItemId()) |
| | | .setQuantity(line.getQuantity().negate()) // 出库数量为负数 |
| | | .setQuantity(negateQuantity(line.getQuantity())) // 出库数量为负数 |
| | | .setBatchId(line.getBatchId()).setBatchCode(line.getBatchCode()) |
| | | .setWarehouseId(line.getWarehouseId()).setLocationId(line.getLocationId()).setAreaId(line.getAreaId()) |
| | | .setBizType(MesBizTypeConstants.WM_MISC_ISSUE).setBizId(issue.getId()).setBizCode(issue.getCode()).setBizLineId(line.getId()))); |
| | | } |
| | | |
| | | /** |
| | | * 出库数量取负:数量为空时抛出明确的业务异常,避免 NPE |
| | | */ |
| | | private BigDecimal negateQuantity(BigDecimal quantity) { |
| | | if (quantity == null) { |
| | | throw exception(WM_MISC_ISSUE_QUANTITY_INVALID); |
| | | } |
| | | return quantity.negate(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void cancelMiscIssue(Long id) { |
| | |
| | | wmTransactionService.createTransactionList(convertList(lines, line -> new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.IN.getType()).setItemId(line.getItemId()) |
| | | .setQuantity(line.getQuantity()) // 入库数量为正数 |
| | | .setBatchCode(line.getBatchCode()) // 批次管理物料需携带批次号 |
| | | .setWarehouseId(line.getWarehouseId()).setLocationId(line.getLocationId()).setAreaId(line.getAreaId()) |
| | | .setBizType(MesBizTypeConstants.WM_MISC_RECPT).setBizId(receipt.getId()).setBizCode(receipt.getCode()).setBizLineId(line.getId()))); |
| | | } |
| | |
| | | @Resource |
| | | @Lazy |
| | | private MesWmReturnVendorLineService returnVendorLineService; |
| | | // 与 ReturnVendorServiceImpl 相互引用,须用 @Lazy 打破循环 |
| | | @Resource |
| | | @Lazy |
| | | private MesWmReturnVendorService returnVendorService; |
| | | @Resource |
| | | private MesMdmItemService mdmItemService; |
| | | @Resource |
| | |
| | | * 校验明细创建/修改的公共数据 |
| | | */ |
| | | private void validateDetailSaveData(MesWmReturnVendorDetailSaveReqVO reqVO) { |
| | | // 校验父单(退货单)处于准备中状态,审批期间及之后禁止增删改明细 |
| | | returnVendorService.validateReturnVendorExistsAndPrepare(reqVO.getReturnId()); |
| | | // 校验父数据(行)存在 |
| | | MesWmReturnVendorLineDO line = returnVendorLineService.validateReturnVendorLineExists(reqVO.getLineId()); |
| | | if (ObjUtil.notEqual(line.getReturnId(), reqVO.getReturnId())) { |
| | |
| | | @Override |
| | | public void deleteReturnVendorDetail(Long id) { |
| | | // 校验存在 |
| | | validateReturnVendorDetailExists(id); |
| | | MesWmReturnVendorDetailDO detail = validateReturnVendorDetailExists(id); |
| | | // 校验父单处于准备中状态,审批期间及之后禁止删除明细 |
| | | returnVendorService.validateReturnVendorExistsAndPrepare(detail.getReturnId()); |
| | | // 删除 |
| | | returnVendorDetailMapper.deleteById(id); |
| | | } |
| | |
| | | returnVendorDetailMapper.deleteByLineId(lineId); |
| | | } |
| | | |
| | | private void validateReturnVendorDetailExists(Long id) { |
| | | if (returnVendorDetailMapper.selectById(id) == null) { |
| | | private MesWmReturnVendorDetailDO validateReturnVendorDetailExists(Long id) { |
| | | MesWmReturnVendorDetailDO detail = returnVendorDetailMapper.selectById(id); |
| | | if (detail == null) { |
| | | throw exception(WM_RETURN_VENDOR_DETAIL_NOT_EXISTS); |
| | | } |
| | | return detail; |
| | | } |
| | | |
| | | /** |
| | |
| | | void auditReturnVendor(Long id, Boolean pass, String reviewRemark); |
| | | |
| | | /** |
| | | * 执行拣货(待拣货 -> 待执行退货) |
| | | * 执行拣货校验(仅校验已审批单据的明细数量一致性,不修改单据状态) |
| | | * |
| | | * 单据状态只能由审核(APPROVING → APPROVED)与退货(APPROVED → FINISHED)推进。 |
| | | * |
| | | * @param id 编号 |
| | | */ |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void stockReturnVendor(Long id) { |
| | | // 校验存在 |
| | | // 校验存在 + 已审批(状态只能由 audit 推进:APPROVING → APPROVED) |
| | | MesWmReturnVendorDO returnVendor = validateReturnVendorExists(id); |
| | | if (ObjUtil.notEqual(MesWmReturnVendorStatusEnum.APPROVING.getStatus(), returnVendor.getStatus())) { |
| | | if (ObjUtil.notEqual(MesWmReturnVendorStatusEnum.APPROVED.getStatus(), returnVendor.getStatus())) { |
| | | throw exception(WM_RETURN_VENDOR_STATUS_INVALID); |
| | | } |
| | | // 执行拣货(待拣货 -> 待执行退货) |
| | | returnVendorMapper.updateById(new MesWmReturnVendorDO() |
| | | .setId(id).setStatus(MesWmReturnVendorStatusEnum.APPROVED.getStatus())); |
| | | // 仅校验行数量与明细数量一致,不修改单据状态 |
| | | if (!Boolean.TRUE.equals(checkReturnVendorQuantity(id))) { |
| | | throw exception(WM_RETURN_VENDOR_DETAIL_QUANTITY_MISMATCH); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | |
| | | if (CollUtil.isEmpty(details)) { |
| | | throw exception(WM_RETURN_VENDOR_NO_DETAIL); |
| | | } |
| | | // 1.3 校验每行明细数量之和等于行退货数量,避免出库数量与单据不一致 |
| | | if (!Boolean.TRUE.equals(checkReturnVendorQuantity(id))) { |
| | | throw exception(WM_RETURN_VENDOR_DETAIL_QUANTITY_MISMATCH); |
| | | } |
| | | |
| | | // 2. 遍历所有明细,创建库存事务(扣减库存 + 记录流水) |
| | | createTransactionList(returnVendor, details); |
| | |
| | | private void createTransactionList(MesWmReturnVendorDO returnVendor, List<MesWmReturnVendorDetailDO> details) { |
| | | wmTransactionService.createTransactionList(convertList(details, detail -> new MesWmTransactionSaveReqDTO() |
| | | .setType(MesWmTransactionTypeEnum.OUT.getType()).setItemId(detail.getItemId()) |
| | | .setQuantity(detail.getQuantity().negate()) // 出库数量为负数 |
| | | .setQuantity(negateQuantity(detail.getQuantity())) // 出库数量为负数 |
| | | .setBatchId(detail.getBatchId()).setBatchCode(detail.getBatchCode()) |
| | | .setWarehouseId(detail.getWarehouseId()).setLocationId(detail.getLocationId()).setAreaId(detail.getAreaId()) |
| | | .setVendorId(returnVendor.getVendorId()) |
| | |
| | | .setBizCode(returnVendor.getCode()).setBizLineId(detail.getLineId()))); |
| | | } |
| | | |
| | | /** |
| | | * 出库数量取负:数量为空时抛出明确的业务异常,避免 NPE |
| | | */ |
| | | private BigDecimal negateQuantity(BigDecimal quantity) { |
| | | if (quantity == null) { |
| | | throw exception(WM_RETURN_VENDOR_DETAIL_QUANTITY_INVALID); |
| | | } |
| | | return quantity.negate(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void cancelReturnVendor(Long id) { |
| | |
| | | } |
| | | // 0. 校验盘点任务处于盘点中状态(与人工录入盘点结果口径一致,仅盘点中可导入) |
| | | stockTakingTaskService.validateStockTakingTaskExistsAndApproving(taskId); |
| | | // 0.1 结果审批已提交且未审核时,盘点结果已锁定,禁止再导入实盘数量 |
| | | stockTakingTaskService.validateResultApprovalNotPending(taskId); |
| | | // 1. 获取盘点任务行 |
| | | List<MesWmStockTakingTaskLineDO> lines = stockTakingTaskLineMapper.selectListByTaskId(taskId); |
| | | if (CollUtil.isEmpty(lines)) { |
| | |
| | | |
| | | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_STOCK_TAKING_TASK_LINE_ALREADY_TAKEN; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_STOCK_TAKING_TASK_LINE_NOT_MATCH; |
| | | import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_STOCK_TAKING_TASK_RESULT_NOT_EXISTS; |
| | | |
| | | /** |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Long createStockTakingTaskResult(MesWmStockTakingTaskResultSaveReqVO createReqVO) { |
| | | // 1. 校验任务处于盘点中状态 |
| | | // 1. 校验任务处于盘点中状态,且结果审批已提交、未审核时禁止写入 |
| | | stockTakingTaskService.validateStockTakingTaskExistsAndApproving(createReqVO.getTaskId()); |
| | | stockTakingTaskService.validateResultApprovalNotPending(createReqVO.getTaskId()); |
| | | |
| | | // 2. 确定 lineId 和账面数量 |
| | | Long lineId = createReqVO.getLineId(); |
| | |
| | | } else { |
| | | // 2.3 如果传递了 lineId,从 line 中获取 quantity |
| | | existingLine = stockTakingTaskLineService.validateStockTakingTaskLineExists(lineId); |
| | | // 2.4 防止串单:盘点行必须属于请求指定的盘点任务 |
| | | if (ObjUtil.notEqual(existingLine.getTaskId(), createReqVO.getTaskId())) { |
| | | throw exception(WM_STOCK_TAKING_TASK_LINE_NOT_MATCH); |
| | | } |
| | | } |
| | | if (existingLine != null |
| | | && existingLine.getTakingQuantity() != null |
| | | && existingLine.getTakingQuantity().compareTo(BigDecimal.ZERO) > 0) { |
| | | // 2.5 防止重复:同一盘点任务行只允许存在一条盘点结果(无论实盘数量是否为 0) |
| | | Long finalLineId = lineId; |
| | | boolean resultExists = stockTakingTaskResultMapper.selectListByTaskId(createReqVO.getTaskId()).stream() |
| | | .anyMatch(result -> Objects.equals(result.getLineId(), finalLineId)); |
| | | if (resultExists) { |
| | | throw exception(WM_STOCK_TAKING_TASK_LINE_ALREADY_TAKEN); |
| | | } |
| | | BigDecimal quantity = existingLine != null ? existingLine.getQuantity() : BigDecimal.ZERO; // 账面数量 |
| | |
| | | updateReqVO.setLineId(null); // lineId 不能修改,避免误操作 |
| | | // 1.1 校验记录存在 |
| | | MesWmStockTakingTaskResultDO oldResult = validateStockTakingTaskResultExists(updateReqVO.getId()); |
| | | // 1.2 校验任务处于盘点中状态 |
| | | // 1.2 校验任务处于盘点中状态,且结果审批已提交、未审核时禁止修改 |
| | | stockTakingTaskService.validateStockTakingTaskExistsAndApproving(oldResult.getTaskId()); |
| | | stockTakingTaskService.validateResultApprovalNotPending(oldResult.getTaskId()); |
| | | |
| | | // 2. 更新 result 记录 |
| | | MesWmStockTakingTaskResultDO result = BeanUtils.toBean(updateReqVO, MesWmStockTakingTaskResultDO.class); |
| | |
| | | public void deleteStockTakingTaskResult(Long id) { |
| | | // 1.1 校验 result 是否存在 |
| | | MesWmStockTakingTaskResultDO result = validateStockTakingTaskResultExists(id); |
| | | // 1.2 校验 task 是否处于 APPROVING 状态 |
| | | // 1.2 校验 task 是否处于 APPROVING 状态,且结果审批已提交、未审核时禁止删除 |
| | | stockTakingTaskService.validateStockTakingTaskExistsAndApproving(result.getTaskId()); |
| | | stockTakingTaskService.validateResultApprovalNotPending(result.getTaskId()); |
| | | |
| | | // 2. 删除 result 记录 |
| | | stockTakingTaskResultMapper.deleteById(id); |
| | | |
| | | // 3. 更新对应 line 的盘点数量和状态 |
| | | // 3. 按剩余盘点结果重算对应 line 的实盘数量(无剩余结果时置 0),避免覆盖成负数 |
| | | BigDecimal remainingTakingQuantity = stockTakingTaskResultMapper.selectListByTaskId(result.getTaskId()).stream() |
| | | .filter(item -> Objects.equals(item.getLineId(), result.getLineId())) |
| | | .map(MesWmStockTakingTaskResultDO::getTakingQuantity) |
| | | .filter(Objects::nonNull) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | stockTakingTaskLineService.updateStockTakingTaskLineTakingQuantity( |
| | | result.getLineId(), result.getTakingQuantity().negate()); |
| | | result.getLineId(), remainingTakingQuantity); |
| | | } |
| | | |
| | | @Override |
| | |
| | | MesWmStockTakingTaskDO validateStockTakingTaskExistsAndApproving(Long id); |
| | | |
| | | /** |
| | | * 校验盘点任务的结果审批未处于「已提交、待审核」状态 |
| | | * |
| | | * 该阶段盘点结果已被锁定,禁止新增、修改、删除盘点结果或导入实盘数量。 |
| | | * |
| | | * @param id 盘点任务编号 |
| | | */ |
| | | void validateResultApprovalNotPending(Long id); |
| | | |
| | | /** |
| | | * 分页查询盘点任务 |
| | | * |
| | | * @param pageReqVO 分页查询条件 |
| | |
| | | return task.getReviewerId() == null && task.getReviewTime() != null; |
| | | } |
| | | |
| | | @Override |
| | | public void validateResultApprovalNotPending(Long id) { |
| | | MesWmStockTakingTaskDO task = validateStockTakingTaskExists(id); |
| | | if (isResultApprovalPending(task)) { |
| | | throw exception(WM_STOCK_TAKING_TASK_RESULT_APPROVAL_PENDING); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取用户昵称 |
| | | * |
| | |
| | | primary: master |
| | | datasource: |
| | | master: |
| | | url: jdbc:mysql://localhost:3306/mom-xgdl?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 |
| | | url: jdbc:mysql://192.168.197.128:3306/mom-xgdl?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 |
| | | username: root |
| | | password: 123456 |
| | | password: sugaozhixing.cn |
| | | |
| | | # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 |
| | | data: |
| | | redis: |
| | | host: localhost # 地址 |
| | | host: 192.168.197.128 # 地址 |
| | | port: 6379 # 端口 |
| | | database: 0 # 数据库索引 |
| | | # password: 123456 |
| | | password: sugaozhixing.cn |
| | | |
| | | --- #################### 定时任务相关配置 #################### |
| | | |
| | |
| | | storage: # 文件上传配置 |
| | | path: D:/uploads # 文件存储根目录(按实际服务器路径配置) |
| | | url-prefix: /admin-api/system/storage-blob # URL路径前缀 |
| | | domain: http://192.168.0.10:48080 # 域名前缀(按实际域名配置) |
| | | domain: http://127.0.0.1:48080 # 域名前缀(按实际域名配置) |
| | | expired: 120 # token过期时间(分钟) |
| | | use-limit: 10 # token使用次数上限 |
| | | jwt-secret: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFG # JWT密钥(至少32字符) |