From 4ce7615b2a4edbbe7bfe1bebfd2d89236ca11c83 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 15 Nov 2024 12:51:37 +0800 Subject: [PATCH 01/18] =?UTF-8?q?refactor(bpm):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E5=AE=9E=E4=BE=8B=E6=9C=8D=E5=8A=A1=E5=92=8C?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E6=8A=84=E9=80=81=20mapper-=20=E5=B0=86=20Bp?= =?UTF-8?q?mProcessCcMapper=20=E4=B8=AD=E7=9A=84=20eqIfPresent=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=20likeIfPresent=EF=BC=8C=E6=8F=90=E9=AB=98=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E7=81=B5=E6=B4=BB=E6=80=A7-=20=E4=BC=98=E5=8C=96=20Bp?= =?UTF-8?q?mProcessInstanceServiceImpl=20=E4=B8=AD=E7=9A=84=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=BB=84=E5=92=8C=E6=8A=84=E9=80=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=20-=20=E6=B7=BB=E5=8A=A0=E7=A9=BA=E9=9B=86=E5=90=88=E5=88=A4?= =?UTF-8?q?=E6=96=AD=EF=BC=8C=E9=81=BF=E5=85=8D=E4=B8=8D=E5=BF=85=E8=A6=81?= =?UTF-8?q?=E7=9A=84=E6=93=8D=E4=BD=9C=20-=20=E8=B0=83=E6=95=B4=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F=EF=BC=8C=E6=8F=90=E9=AB=98=E5=8F=AF?= =?UTF-8?q?=E8=AF=BB=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/dal/mysql/definition/BpmProcessCcMapper.java | 2 +- .../module/bpm/service/task/BpmProcessInstanceServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessCcMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessCcMapper.java index f12543e0..94090084 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessCcMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessCcMapper.java @@ -20,7 +20,7 @@ public interface BpmProcessCcMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(BpmProcessCcDO::getName, reqVO.getName()) .likeIfPresent(BpmProcessCcDO::getUserGroupId, reqVO.getUserGroupId()) - .eqIfPresent(BpmProcessCcDO::getCompanyDeptId, reqVO.getCompanyDeptId()) + .likeIfPresent(BpmProcessCcDO::getCompanyDeptId, reqVO.getCompanyDeptId()) .eqIfPresent(BpmProcessCcDO::getStatus, reqVO.getStatus()) .orderByDesc(BpmProcessCcDO::getId)); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 75905129..153de2c9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.DynamicMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessCcService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOACashService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); // 查询流程变量 List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(paramMap)); // 创建流程后,添加抄送人 processCCToUsers(instance); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) @DataPermission(enable = false) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(id) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @param * @return */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; } catch (Exception exception) { exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId(); List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setCcids(ccIds) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO(); String key = reqVO.getKey(); //流程标识 String processInstanceId = reqVO.getId(); //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId); bpmProcessInstancePrintDataRespVO.setKey(key); BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId); Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.DynamicMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessCcService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOACashService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); // 查询流程变量 List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(paramMap)); // 创建流程后,添加抄送人 processCCToUsers(instance); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) @DataPermission(enable = false) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(id) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @param * @return */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; } catch (Exception exception) { exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId(); List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setCcids(ccIds) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } } @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO(); String key = reqVO.getKey(); //流程标识 String processInstanceId = reqVO.getId(); //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId); bpmProcessInstancePrintDataRespVO.setKey(key); BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId); Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file From 51686c071fe0c21cdee476b1570ccd243a5f6e9b Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sun, 17 Nov 2024 17:20:47 +0800 Subject: [PATCH 02/18] =?UTF-8?q?feat(bpm):=20=E5=88=86=E7=A6=BB=E5=A4=87?= =?UTF-8?q?=E7=94=A8=E9=87=91=E9=87=91=E9=A2=9D=E4=B8=8E=E5=89=A9=E4=BD=99?= =?UTF-8?q?=E9=87=91=E9=A2=9D=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 BpmOACashRespVO 和 BpmOAReimbursementRespVO 中添加 remainingAmount 字段 - 修改 BpmProcessInstanceServiceImpl 中的逻辑,分别设置 amount 和 remainingAmount - 此修改提高了数据的准确性和可靠性,避免了之前金额混淆的问题 --- .../bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java | 3 +++ .../admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java | 5 ++++- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java index bb9ac6c2..9228d0ae 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java @@ -46,6 +46,9 @@ public class BpmOACashRespVO extends BpmOABaseRespVO { @Schema(description = "备用金金额") private BigDecimal amount; + @Schema(description = "备用金剩余金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private BigDecimal remainingAmount; + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) private List fileItems; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java index 0a9f68af..73d29593 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java @@ -44,7 +44,10 @@ public class BpmOAReimbursementRespVO extends BpmOABaseRespVO { private BigDecimal reimbursementType ; @Schema(description = "备用金金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) - private BigDecimal amount ; + private BigDecimal amount; + + @Schema(description = "备用金剩余金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private BigDecimal remainingAmount; @Schema(description = "备用金ID") private Long imprestId; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 153de2c9..fcfbf2b3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.DynamicMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessCcService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOACashService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); // 查询流程变量 List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(paramMap)); // 创建流程后,添加抄送人 processCCToUsers(instance); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) @DataPermission(enable = false) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(id) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @param * @return */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; } catch (Exception exception) { exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId(); List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setCcids(ccIds) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } } @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO(); String key = reqVO.getKey(); //流程标识 String processInstanceId = reqVO.getId(); //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId); bpmProcessInstancePrintDataRespVO.setKey(key); BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId); Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.DynamicMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessCcService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOACashService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); // 查询流程变量 List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(paramMap)); // 创建流程后,添加抄送人 processCCToUsers(instance); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) @DataPermission(enable = false) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(id) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @param * @return */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; } catch (Exception exception) { exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId(); List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setCcids(ccIds) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } } @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO(); String key = reqVO.getKey(); //流程标识 String processInstanceId = reqVO.getId(); //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId); bpmProcessInstancePrintDataRespVO.setKey(key); BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId); Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 bpmOAReimbursementRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 cashRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file From 169c30f39554f26bd016645997062897741e1199 Mon Sep 17 00:00:00 2001 From: aikai Date: Sat, 23 Nov 2024 10:04:05 +0800 Subject: [PATCH 03/18] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=91=A8=E6=9C=AB?= =?UTF-8?q?=E6=89=93=E5=8D=A1=E6=89=93=E5=8D=A1=E7=8A=B6=E6=80=81=E8=AE=A1?= =?UTF-8?q?=E7=AE=97bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/attendance/vo/AttendancePunchPageVO.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendancePunchPageVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendancePunchPageVO.java index 2e6113d8..15676f9e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendancePunchPageVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/attendance/vo/AttendancePunchPageVO.java @@ -77,13 +77,14 @@ public class AttendancePunchPageVO { /** * 处理加班打卡 不计算是否迟到早退 + * * @param punchType */ public void setPunchType(Integer punchType) { - if (this.getFieldworkFlag() == 0) { + if (this.getWorkOvertimeFlag() == 0) { this.punchType = punchType; } else { - this.punchType = Arrays.asList(0, 2).contains(punchType) ? 0 : 1; + this.punchType = Arrays.asList(0, 2).contains(punchType) ? 0 : (Arrays.asList(1, 3).contains(punchType) ? 1 : 4); } } } From 90fd403d9a926f02dfe7ffbf50007e7610b1f850 Mon Sep 17 00:00:00 2001 From: aikai Date: Sat, 23 Nov 2024 10:30:01 +0800 Subject: [PATCH 04/18] =?UTF-8?q?=E5=85=B3=E9=97=AD=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=90=8E=E5=B0=86=E5=BD=93=E5=89=8D=E7=94=A8=E6=88=B7=E7=A7=BB?= =?UTF-8?q?=E5=87=BA=E5=BD=93=E5=89=8D=E7=94=A8=E6=88=B7=E6=89=80=E5=9C=A8?= =?UTF-8?q?=E7=9A=84=E8=80=83=E5=8B=A4=E7=BB=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/system/service/user/AdminUserServiceImpl.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index 4a95314d..13bca1e4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -26,9 +26,11 @@ import cn.iocoder.yudao.module.system.controller.admin.user.vo.factoryUser.Facto import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdatePasswordReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.profile.UserProfileUpdateReqVO; import cn.iocoder.yudao.module.system.controller.admin.user.vo.user.*; +import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.UserPostDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper; import cn.iocoder.yudao.module.system.dal.mysql.dept.UserPostMapper; import cn.iocoder.yudao.module.system.dal.mysql.user.AdminUserMapper; import cn.iocoder.yudao.module.system.service.dept.DeptService; @@ -88,6 +90,8 @@ public class AdminUserServiceImpl implements AdminUserService { @Resource private UserPostMapper userPostMapper; + @Resource + private AttendanceGroupUserMapper attendanceGroupUserMapper; @Resource private FileApi fileApi; @@ -264,6 +268,9 @@ public class AdminUserServiceImpl implements AdminUserService { case 1: // 关闭状态 设置用户编制为离职 updateObj.setUserStaffing(8); + // -- 将当前用户移除所在考情组 + attendanceGroupUserMapper.delete(new LambdaQueryWrapper() + .eq(AttendanceGroupUserDO::getUserId, id)); break; } userMapper.updateById(updateObj); @@ -745,7 +752,7 @@ public class AdminUserServiceImpl implements AdminUserService { @Override public List getAllList(Integer status, Integer type, List userIds) { - if (CollUtil.isEmpty(userIds)){ + if (CollUtil.isEmpty(userIds)) { return Collections.emptyList(); } return userMapper.selectList(new LambdaQueryWrapper() From d16f54c3e649fc51dade8680cbc5fe05d391affc Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sat, 23 Nov 2024 10:52:13 +0800 Subject: [PATCH 05/18] =?UTF-8?q?feat(system):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加项目管理相关的数据对象、控制器、服务接口和实现类 - 实现项目管理的 CRUD 功能,包括创建、更新、删除和查询项目信息 - 添加租赁客户管理功能 - 优化文件更新接口,支持批量更新- 新增用户信息查询接口- 添加系统错误码常量 --- .../bpm/dal/dataobject/oa/BpmOARefundDO.java | 38 ++++ .../yudao/module/infra/api/file/FileApi.java | 7 +- .../module/infra/api/file/FileApiImpl.java | 4 +- .../infra/service/file/FileService.java | 2 +- .../infra/service/file/FileServiceImpl.java | 7 +- .../system/enums/ErrorCodeConstants.java | 12 ++ .../admin/project/ProjectController.java | 177 ++++++++++++++++++ .../admin/project/vo/ProjectPageReqVO.java | 53 ++++++ .../admin/project/vo/ProjectRespVO.java | 72 +++++++ .../admin/project/vo/ProjectSaveReqVO.java | 69 +++++++ .../rental/RentalCustomerController.java | 97 ++++++++++ .../rental/RentalDepositRecordController.java | 64 +++++++ .../rental/RentalItemsRecordController.java | 76 ++++++++ .../admin/rental/RentalOrderController.java | 108 +++++++++++ .../vo/customer/RentalCustomerPageReqVO.java | 40 ++++ .../vo/customer/RentalCustomerRespVO.java | 37 ++++ .../vo/customer/RentalCustomerSaveReqVO.java | 36 ++++ .../customer/RentalCustomerStatusReqVO.java | 18 ++ .../vo/itemsrecord/RentalItemsCountReqVO.java | 15 ++ .../RentalItemsRecordPageReqVO.java | 32 ++++ .../itemsrecord/RentalItemsRecordRespVO.java | 30 +++ .../RentalItemsRecordSaveReqVO.java | 32 ++++ .../rental/vo/order/RentalOrderPageReqVO.java | 39 ++++ .../rental/vo/order/RentalOrderRespVO.java | 57 ++++++ .../rental/vo/order/RentalOrderSaveReqVO.java | 48 +++++ .../RentalDepositAmountReqVO.java | 17 ++ .../RentalDepositRecordPageReqVO.java | 42 +++++ .../RentalDepositRecordRespVO.java | 63 +++++++ .../RentalDepositRecordSaveReqVO.java | 53 ++++++ .../controller/admin/user/UserController.java | 10 + .../dal/dataobject/project/ProjectDO.java | 94 ++++++++++ .../dataobject/rental/RentalCustomerDO.java | 54 ++++++ .../rental/RentalDepositRecordDO.java | 74 ++++++++ .../rental/RentalItemsRecordDO.java | 44 +++++ .../dal/dataobject/rental/RentalOrderDO.java | 60 ++++++ .../dal/mysql/project/ProjectMapper.java | 32 ++++ .../mysql/rental/RentalCustomerMapper.java | 29 +++ .../rental/RentalDepositRecordMapper.java | 35 ++++ .../mysql/rental/RentalItemsRecordMapper.java | 29 +++ .../dal/mysql/rental/RentalOrderMapper.java | 49 +++++ .../system/dal/redis/RedisKeyConstants.java | 7 + .../service/project/ProjectService.java | 55 ++++++ .../service/project/ProjectServiceImpl.java | 73 ++++++++ .../service/rental/RentalCustomerService.java | 69 +++++++ .../rental/RentalCustomerServiceImpl.java | 91 +++++++++ .../rental/RentalDepositRecordService.java | 64 +++++++ .../RentalDepositRecordServiceImpl.java | 129 +++++++++++++ .../rental/RentalItemsRecordService.java | 60 ++++++ .../rental/RentalItemsRecordServiceImpl.java | 111 +++++++++++ .../service/rental/RentalOrderService.java | 63 +++++++ .../rental/RentalOrderServiceImpl.java | 148 +++++++++++++++ .../system/service/user/AdminUserService.java | 9 + .../service/user/AdminUserServiceImpl.java | 8 + .../rental/RentalDepositRecordMapper.xml | 25 +++ .../mapper/rental/RentalItemsRecordMapper.xml | 24 +++ .../mapper/rental/RentalOrderMapper.xml | 21 +++ 56 files changed, 2800 insertions(+), 12 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalCustomerController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalDepositRecordController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerStatusReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsCountReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositAmountReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/project/ProjectDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalCustomerDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalDepositRecordDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalItemsRecordDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalCustomerMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalDepositRecordMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalOrderMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalDepositRecordMapper.xml create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalOrderMapper.xml diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java new file mode 100644 index 00000000..f359ff51 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * OA 转正申请 DO + * + * + * @author 符溶馨 + + */ +@TableName(value ="bpm_oa_refund", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOARefundDO extends BaseDO { + + /** + * 出差表单主键 + */ + @TableId + private Long id; + + /** + * 申请人的用户编号 + * 关联 AdminUserDO 的 id 属性 + */ + private Long userId; + + private String orderNo; + +} diff --git a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java index cb069631..efff9173 100644 --- a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java +++ b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java @@ -83,10 +83,9 @@ public interface FileApi { @RequestBody byte[] content); @PostMapping(PREFIX + "/updateBusinessFile") - @Operation(summary = "修改BusinessFile文件中的 businessInstanceId | 入职申请用") - CommonResult updateBusinessFileFormEntry(@RequestParam("url") String url, - @RequestParam("businessInstanceId") String businessInstanceId); - + @Operation(summary = "修改BusinessFile文件中的 businessInstanceId") + CommonResult updateBusinessFile(@RequestParam("url") List url, + @RequestParam("businessInstanceId") String businessInstanceId); @DeleteMapping(PREFIX + "/deleteBpmFile") @Operation(summary = "删除工作流附件") diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java index 2c84494c..d4bc6a19 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java @@ -67,9 +67,9 @@ public class FileApiImpl implements FileApi { @Override @SneakyThrows - public CommonResult updateBusinessFileFormEntry(String url, String businessInstanceId) { + public CommonResult updateBusinessFile(List url, String businessInstanceId) { - fileService.uploadBusinessFileFormEntry(url, businessInstanceId); + fileService.uploadBusinessFile(url, businessInstanceId); return success(true); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java index a4d2b716..615a5f82 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java @@ -109,7 +109,7 @@ public interface FileService { * 更新文件的流程实例ID | 入职申请用 * @param url 文件地址 */ - void uploadBusinessFileFormEntry(String url, String businessInstanceId); + void uploadBusinessFile(List url, String businessInstanceId); /** * 获取用户的签名图片地址 diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index f8fcb47f..0cb0e897 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -337,14 +337,11 @@ public class FileServiceImpl implements FileService { @Override @SneakyThrows - public void uploadBusinessFileFormEntry(String url, String businessInstanceId) { + public void uploadBusinessFile(List url, String businessInstanceId) { LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper<>(); - lambdaUpdateWrapper.eq(BusinessFileDO::getUrl, url); + lambdaUpdateWrapper.in(BusinessFileDO::getUrl, url); lambdaUpdateWrapper.set(BusinessFileDO::getBusinessInstanceId, businessInstanceId); // 假设 bid 是要更新的 bid 值 - lambdaUpdateWrapper.set(BusinessFileDO::getUploadUserId, businessInstanceId); - lambdaUpdateWrapper.set(BusinessFileDO::getCreator, businessInstanceId); - lambdaUpdateWrapper.set(BusinessFileDO::getUpdater, businessInstanceId); // 调用 MyBatis Plus 的 update 方法执行批量更新 businessFileMapper.update(null, lambdaUpdateWrapper); diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index e9d3b11a..8befb466 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -270,4 +270,16 @@ public interface ErrorCodeConstants { ErrorCode PAYSLIP_EXISTS = new ErrorCode(1_012_002_007, "所选公司在当前月份已上传工资条!如需修改,请勾选覆盖导入。"); ErrorCode PAYSLIP_ID_CARD_ERROR = new ErrorCode(1_012_002_008, "【{}】身份证输入有误,请核对后导入!"); ErrorCode PAYSLIP_ISSUED = new ErrorCode(1_012_002_009, "所选公司在当前月份的工资条已下发,不能修改!"); + + // ========== 租赁相关 1-013-001-001 ========== + ErrorCode RENTAL_CUSTOMER_NOT_EXISTS = new ErrorCode(1_013_001_001, "租赁客户不存在"); + ErrorCode RENTAL_ORDER_NOT_EXISTS = new ErrorCode(1_013_001_002, "租赁订单不存在"); + ErrorCode RENTAL_ITEMS_RECORD_NOT_EXISTS = new ErrorCode(1_013_001_003, "租赁物品记录不存在"); + ErrorCode RENTAL_DEPOSIT_RECORD_NOT_EXISTS = new ErrorCode(1_013_001_004, "租赁订单押金记录不存在"); + ErrorCode RENTAL_ITEMS_NUMBER_EXCESS = new ErrorCode(1_013_001_005, "归还数量不能大于剩余租借数量!"); + ErrorCode RENTAL_RECEIVED_AMOUNT_EXCESS = new ErrorCode(1_013_001_006, "收款金额不能大于押金金额!"); + ErrorCode RENTAL_REFUND_AMOUNT_EXCESS = new ErrorCode(1_013_001_007, "退款金额不能大于收款金额!"); + + // ========== 项目管理相关 1-014-001-001 ========== + ErrorCode PROJECT_NOT_EXISTS = new ErrorCode(1_014_001_001, "项目不存在!"); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java new file mode 100644 index 00000000..c77d1c73 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java @@ -0,0 +1,177 @@ +package cn.iocoder.yudao.module.system.controller.admin.project; + +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectRespVO; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.project.ProjectService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.*; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +@Tag(name = "管理后台 - 项目管理") +@RestController +@RequestMapping("/system/project") +@Validated +public class ProjectController { + + @Resource + private ProjectService projectService; + + @Resource + private AdminUserService userService; + + @Resource + private DeptService deptService; + + @PostMapping("/create") + @Operation(summary = "创建项目管理") + @PreAuthorize("@ss.hasPermission('system:project:create')") + public CommonResult createProject(@Valid @RequestBody ProjectSaveReqVO createReqVO) { + return success(projectService.createProject(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新项目管理") + @PreAuthorize("@ss.hasPermission('system:project:update')") + public CommonResult updateProject(@Valid @RequestBody ProjectSaveReqVO updateReqVO) { + projectService.updateProject(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除项目管理") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:project:delete')") + public CommonResult deleteProject(@RequestParam("id") Long id) { + projectService.deleteProject(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得项目管理") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:project:query')") + public CommonResult getProject(@RequestParam("id") Long id) { + ProjectDO project = projectService.getProject(id); + ProjectRespVO respVO = BeanUtils.toBean(project, ProjectRespVO.class); + if (respVO != null) { + // 获取项目中所有人员的用户编号列表 + Set userIds = respVO.getStaff() == null ? new HashSet<>() : respVO.getStaff(); + userIds.add(respVO.getDirectorUserId()); + + // 获取项目中所有部门编号列表 + Set deptIds = respVO.getParticipationDept() == null ? new HashSet<>() : respVO.getParticipationDept(); + deptIds.add(respVO.getResponsibleDept()); + + // 获取所有用户信息 + List userDOS = userService.getUserList(userIds); + Map userMap = convertMap(userDOS, AdminUserDO::getId); + // 获取所有部门信息 + List deptDOS = deptService.getDeptList(deptIds); + Map deptMap = convertMap(deptDOS, DeptDO::getId); + + // 筛选出不是责任人的用户信息 + List userVOs = userDOS.stream() + .filter(user -> !user.getId().equals(respVO.getDirectorUserId())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任人名称 + respVO.setDirectorUserName(userMap.get(respVO.getDirectorUserId()).getNickname()); + // 拼接项目人员名称 + respVO.setStaffName(userVOs.stream().map(AdminUserDO::getNickname).collect(Collectors.joining("、"))); + + // 筛选出不是责任人部门的部门信息 + List deptVOs = deptDOS.stream() + .filter(dept -> !dept.getId().equals(respVO.getResponsibleDept())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任部门名称 + respVO.setResponsibleDeptName(deptMap.get(respVO.getResponsibleDept()).getName()); + // 拼接参与部门名称 + respVO.setParticipationDeptName(deptVOs.stream().map(DeptDO::getName).collect(Collectors.joining("、"))); + } + + return success(respVO); + } + + @GetMapping("/page") + @Operation(summary = "获得项目管理分页") + @PreAuthorize("@ss.hasPermission('system:project:query')") + @DataPermission(enable = false) + public CommonResult> getProjectPage(@Valid ProjectPageReqVO pageReqVO) { + PageResult pageResult = projectService.getProjectPage(pageReqVO); + PageResult respVOs = BeanUtils.toBean(pageResult, ProjectRespVO.class); + + if (CollectionUtil.isNotEmpty(respVOs.getList())) { + // 获取项目中所有人员的用户编号列表 + List userIds = respVOs.getList().stream() + .filter(item -> Objects.nonNull(item.getStaff())) + .flatMap(item -> item.getStaff().stream()) + .collect(Collectors.toList()); + userIds.addAll(convertList(respVOs.getList(), ProjectRespVO::getDirectorUserId)); + + // 获取项目中所有部门编号列表 + List deptIds = respVOs.getList().stream() + .filter(item -> Objects.nonNull(item.getParticipationDept())) + .flatMap(item -> item.getParticipationDept().stream()) + .collect(Collectors.toList()); + deptIds.addAll(convertList(respVOs.getList(), ProjectRespVO::getResponsibleDept)); + + // 获取所有用户信息 + List userDOS = userService.getUserList(userIds); + Map userMap = convertMap(userDOS, AdminUserDO::getId); + // 获取所有部门信息 + List deptDOS = deptService.getDeptList(deptIds); + Map deptMap = convertMap(deptDOS, DeptDO::getId); + respVOs.getList().forEach(item -> { + // 筛选出不是责任人的用户信息 + List userVOs = userDOS.stream() + .filter(user -> !user.getId().equals(item.getDirectorUserId())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任人名称 + item.setDirectorUserName(userMap.get(item.getDirectorUserId()).getNickname()); + // 拼接项目人员名称 + item.setStaffName(userVOs.stream().map(AdminUserDO::getNickname).collect(Collectors.joining("、"))); + + // 筛选出不是责任人部门的部门信息 + List deptVOs = deptDOS.stream() + .filter(dept -> !dept.getId().equals(item.getResponsibleDept())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任部门名称 + item.setResponsibleDeptName(deptMap.get(item.getResponsibleDept()).getName()); + // 拼接参与部门名称 + item.setParticipationDeptName(deptVOs.stream().map(DeptDO::getName).collect(Collectors.joining("、"))); + }); + } + + return success(respVOs); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectPageReqVO.java new file mode 100644 index 00000000..5a597577 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectPageReqVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.system.controller.admin.project.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 项目管理分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProjectPageReqVO extends PageParam { + + @Schema(description = "项目编号") + private String projectNo; + + @Schema(description = "项目类型 | 字典值参考system_project_type", example = "1") + private Integer type; + + @Schema(description = "项目名称") + private String name; + + @Schema(description = "责任部门") + private Long responsibleDept; + + @Schema(description = "参与部门集合") + private String participationDept; + + @Schema(description = "责任人用户编号") + private Long directorUserId; + + @Schema(description = "项目开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDate[] startDate; + + @Schema(description = "项目结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDate[] endDate; + + @Schema(description = "是否长期 | 0否 1是") + private Integer isLongTerm; + + @Schema(description = "项目状态 | 1 进行中 2已完成", example = "1") + private Integer status; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectRespVO.java new file mode 100644 index 00000000..2feec509 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectRespVO.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.system.controller.admin.project.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 项目管理 Response VO") +@Data +public class ProjectRespVO { + + @Schema(description = "项目管理表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "项目编号", requiredMode = Schema.RequiredMode.REQUIRED) + private String projectNo; + + @Schema(description = "项目类型 | 字典值参考system_project_type", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("项目名称") + private String name; + + @Schema(description = "责任部门", requiredMode = Schema.RequiredMode.REQUIRED) + private Long responsibleDept; + + @Schema(description = "责任部门名称") + private String responsibleDeptName; + + @Schema(description = "参与部门集合", requiredMode = Schema.RequiredMode.REQUIRED) + private Set participationDept; + + @Schema(description = "参与部门名称") + private String participationDeptName; + + @Schema(description = "责任人用户编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long directorUserId; + + @Schema(description = "责任人用户名称") + private String directorUserName; + + @Schema(description = "项目开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDate startDate; + + @Schema(description = "项目结束时间") + private LocalDate endDate; + + @Schema(description = "是否长期 | 0否 1是") + private Integer isLongTerm; + + @Schema(description = "项目预算") + private Integer projectBudget; + + @Schema(description = "项目内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String content; + + @Schema(description = "项目人员用户编号集合") + private Set staff; + + @Schema(description = "项目人员用户名称") + private String staffName; + + @Schema(description = "项目状态 | 1 进行中 2已完成", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java new file mode 100644 index 00000000..950dfe6f --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.system.controller.admin.project.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; +import java.util.Map; +import java.util.Set; + +@Schema(description = "管理后台 - 项目管理新增/修改 Request VO") +@Data +public class ProjectSaveReqVO { + + @Schema(description = "项目管理表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "项目编号") + private String projectNo; + + @Schema(description = "项目类型 | 字典值参考system_project_type", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "项目类型 | 字典值参考system_project_type不能为空") + private Integer type; + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "项目名称不能为空") + private String name; + + @Schema(description = "责任部门", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任部门不能为空") + private Long responsibleDept; + + @Schema(description = "参与部门集合", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "参与部门集合不能为空") + private Set participationDept; + + @Schema(description = "责任人用户编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任人用户编号不能为空") + private Long directorUserId; + + @Schema(description = "项目开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目开始时间不能为空") + private LocalDate startDate; + + @Schema(description = "项目结束时间") + private LocalDate endDate; + + @Schema(description = "是否长期 | 0否 1是") + private Integer isLongTerm; + + @Schema(description = "项目预算") + private Integer projectBudget; + + @Schema(description = "项目内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "项目内容不能为空") + private String content; + + @Schema(description = "项目人员用户编号集合") + private Set staff; + + @Schema(description = "项目额外属性") + private Map dynamicAttribute; + + @Schema(description = "项目状态 | 1 进行中 2已完成", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "项目状态 | 1 进行中 2已完成不能为空") + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalCustomerController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalCustomerController.java new file mode 100644 index 00000000..f0e48d98 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalCustomerController.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerStatusReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.service.rental.RentalCustomerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + + +@Tag(name = "管理后台 - 租赁客户") +@RestController +@RequestMapping("/system/rental-customer") +@Validated +public class RentalCustomerController { + + @Resource + private RentalCustomerService rentalCustomerService; + + @PostMapping("/create") + @Operation(summary = "创建租赁客户") + @PreAuthorize("@ss.hasPermission('system:rental-customer:create')") + public CommonResult createRentalCustomer(@Valid @RequestBody RentalCustomerSaveReqVO createReqVO) { + return success(rentalCustomerService.createRentalCustomer(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租赁客户") + @PreAuthorize("@ss.hasPermission('system:rental-customer:update')") + public CommonResult updateRentalCustomer(@Valid @RequestBody RentalCustomerSaveReqVO updateReqVO) { + rentalCustomerService.updateRentalCustomer(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新租赁客户状态") + @PreAuthorize("@ss.hasPermission('system:rental-customer:update')") + public CommonResult updateRentalCustomer(@RequestBody RentalCustomerStatusReqVO updateReqVO) { + rentalCustomerService.updateRentalCustomerStatus(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租赁客户") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:rental-customer:delete')") + public CommonResult deleteRentalCustomer(@RequestParam("id") Long id) { + rentalCustomerService.deleteRentalCustomer(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租赁客户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:rental-customer:query')") + public CommonResult getRentalCustomer(@RequestParam("id") Long id) { + RentalCustomerDO rentalCustomer = rentalCustomerService.getRentalCustomer(id); + return success(BeanUtils.toBean(rentalCustomer, RentalCustomerRespVO.class)); + } + + @GetMapping("/get-list") + @Operation(summary = "获得开启状态的租赁客户列表") + @PreAuthorize("@ss.hasPermission('system:rental-customer:query')") + public CommonResult> getRentalCustomerList() { + List rentalCustomer = rentalCustomerService.getRentalCustomerList(); + return success(BeanUtils.toBean(rentalCustomer, RentalCustomerRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租赁客户分页") + @PreAuthorize("@ss.hasPermission('system:rental-customer:query')") + public CommonResult> getRentalCustomerPage(@Valid RentalCustomerPageReqVO pageReqVO) { + PageResult pageResult = rentalCustomerService.getRentalCustomerPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, RentalCustomerRespVO.class)); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalDepositRecordController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalDepositRecordController.java new file mode 100644 index 00000000..867eadbb --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalDepositRecordController.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import cn.iocoder.yudao.module.system.service.rental.RentalDepositRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + + +@Tag(name = "管理后台 - 租赁订单押金记录") +@RestController +@RequestMapping("/system/rental-deposit-record") +@Validated +public class RentalDepositRecordController { + + @Resource + private RentalDepositRecordService rentalDepositRecordService; + + @PostMapping("/create") + @Operation(summary = "创建租赁订单押金记录") + @PreAuthorize("@ss.hasPermission('system:rental-deposit-record:create')") + public CommonResult createRentalDepositRecord(@Valid @RequestBody RentalDepositRecordSaveReqVO createReqVO) { + return success(rentalDepositRecordService.createRentalDepositRecord(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租赁订单押金记录") + @PreAuthorize("@ss.hasPermission('system:rental-deposit-record:update')") + public CommonResult updateRentalDepositRecord(@Valid @RequestBody RentalDepositRecordSaveReqVO updateReqVO) { + rentalDepositRecordService.updateRentalDepositRecord(updateReqVO); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租赁订单押金记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:rental-deposit-record:query')") + public CommonResult getRentalDepositRecord(@RequestParam("id") Long id) { + RentalDepositRecordDO rentalDepositRecord = rentalDepositRecordService.getRentalDepositRecord(id); + return success(BeanUtils.toBean(rentalDepositRecord, RentalDepositRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租赁订单押金记录分页") + @PreAuthorize("@ss.hasPermission('system:rental-deposit-record:query')") + public CommonResult> getRentalDepositRecordPage(@Valid RentalDepositRecordPageReqVO pageReqVO) { + PageResult pageResult = rentalDepositRecordService.getRentalDepositRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, RentalDepositRecordRespVO.class)); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java new file mode 100644 index 00000000..3183f197 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalItemsRecordDO; +import cn.iocoder.yudao.module.system.service.rental.RentalItemsRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 租赁物品记录") +@RestController +@RequestMapping("/system/rental-items") +@Validated +public class RentalItemsRecordController { + + @Resource + private RentalItemsRecordService rentalItemsRecordService; + + @PostMapping("/create") + @Operation(summary = "创建租赁物品记录") + @PreAuthorize("@ss.hasPermission('system:rental-items:create')") + public CommonResult createRentalItemsRecord(@Valid @RequestBody RentalItemsRecordSaveReqVO createReqVO) { + return success(rentalItemsRecordService.createRentalItemsRecord(createReqVO)); + } + + @PostMapping("/createBatch") + @Operation(summary = "批量创建租赁物品记录") + @PreAuthorize("@ss.hasPermission('system:rental-items:create')") + public CommonResult createRentalItemsRecord(@Valid @RequestBody List createReqVO) { + rentalItemsRecordService.createRentalItemsRecordBath(createReqVO); + return success(true); + } + + @PutMapping("/update") + @Operation(summary = "更新租赁物品记录") + @PreAuthorize("@ss.hasPermission('system:rental-items:update')") + public CommonResult updateRentalItemsRecord(@Valid @RequestBody RentalItemsRecordSaveReqVO updateReqVO) { + rentalItemsRecordService.updateRentalItemsRecord(updateReqVO); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获取租赁物品记录") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:rental-items:query')") + public CommonResult getRentalItemsRecord(@RequestParam("id") Long id) { + + return success(BeanUtils.toBean(rentalItemsRecordService.getRentalItemsRecord(id), RentalItemsRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租赁物品记录分页") + @PreAuthorize("@ss.hasPermission('system:rental-items:query')") + public CommonResult> getRentalItemsRecordPage(@Valid RentalItemsRecordPageReqVO pageReqVO) { + PageResult pageResult = rentalItemsRecordService.getRentalItemsRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, RentalItemsRecordRespVO.class)); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java new file mode 100644 index 00000000..9621d053 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; +import cn.iocoder.yudao.module.system.service.rental.RentalCustomerService; +import cn.iocoder.yudao.module.system.service.rental.RentalDepositRecordService; +import cn.iocoder.yudao.module.system.service.rental.RentalOrderService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + + +@Tag(name = "管理后台 - 租赁订单") +@RestController +@RequestMapping("/system/rental-order") +@Validated +public class RentalOrderController { + + @Resource + private RentalOrderService rentalOrderService; + + @Resource + private RentalCustomerService rentalCustomerService; + + @Resource + private RentalDepositRecordService rentalDepositRecordService; + + @PostMapping("/create") + @Operation(summary = "创建租赁订单") + @PreAuthorize("@ss.hasPermission('system:rental-order:create')") + public CommonResult createRentalOrder(@Valid @RequestBody RentalOrderSaveReqVO createReqVO) { + return success(rentalOrderService.createRentalOrder(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租赁订单") + @PreAuthorize("@ss.hasPermission('system:rental-order:update')") + public CommonResult updateRentalOrder(@Valid @RequestBody RentalOrderSaveReqVO updateReqVO) { + return success(rentalOrderService.updateRentalOrder(updateReqVO)); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租赁订单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:rental-order:delete')") + public CommonResult deleteRentalOrder(@RequestParam("id") Long id) { + rentalOrderService.deleteRentalOrder(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租赁订单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:rental-order:query')") + public CommonResult getRentalOrder(@RequestParam("id") Long id) { + RentalOrderDO rentalOrder = rentalOrderService.getRentalOrder(id); + RentalOrderRespVO respVO = BeanUtils.toBean(rentalOrder, RentalOrderRespVO.class); + + // 获取客户详情 + RentalCustomerDO customerDO = rentalCustomerService.getRentalCustomer(rentalOrder.getCustomerId()); + if (customerDO != null) { + // 设置客户信息 + respVO.setCustomerName(customerDO.getName()); + respVO.setCustomerBankName(customerDO.getBankName()); + respVO.setCustomerBankNo(customerDO.getBankNo()); + } + + // 获取已收金额 + RentalDepositAmountReqVO amountReqVO = rentalDepositRecordService.getRentalDepositRecordAmount(rentalOrder.getOrderNo(), false); + // 设置已收金额 + respVO.setReceivedAmount(amountReqVO.getReceivedAmount()); + // 设置已退金额 + respVO.setRefundAmount(amountReqVO.getRefundAmount()); + + return success(respVO); + } + + @GetMapping("/page") + @Operation(summary = "获得租赁订单分页") + @PreAuthorize("@ss.hasPermission('system:rental-order:query')") + public CommonResult> getRentalOrderPage(@Valid RentalOrderPageReqVO pageReqVO) { + PageResult pageResult = rentalOrderService.getRentalOrderPage(pageReqVO); + return success(pageResult); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerPageReqVO.java new file mode 100644 index 00000000..3ec41554 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerPageReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租赁客户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RentalCustomerPageReqVO extends PageParam { + + @Schema(description = "客户名称", example = "赵六") + private String name; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "开户行", example = "=") + private String bankName; + + @Schema(description = "卡号") + private String bankNo; + + @Schema(description = "剩余押金金额") + private BigDecimal amount; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerRespVO.java new file mode 100644 index 00000000..903b2d89 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerRespVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租赁客户 Response VO") +@Data +public class RentalCustomerRespVO { + + @Schema(description = "租赁客户表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "开户行", requiredMode = Schema.RequiredMode.REQUIRED, example = "=") + private String bankName; + + @Schema(description = "卡号", requiredMode = Schema.RequiredMode.REQUIRED) + private String bankNo; + + @Schema(description = "剩余押金金额") + private BigDecimal amount; + + @Schema(description = "状态 | 0开启 1关闭") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerSaveReqVO.java new file mode 100644 index 00000000..527e0cab --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerSaveReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 租赁客户新增/修改 Request VO") +@Data +public class RentalCustomerSaveReqVO { + + @Schema(description = "租赁客户表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "客户名称不能为空") + private String name; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "开户行", requiredMode = Schema.RequiredMode.REQUIRED, example = "=") + @NotEmpty(message = "开户行不能为空") + private String bankName; + + @Schema(description = "卡号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "卡号不能为空") + private String bankNo; + + @Schema(description = "剩余押金金额") + private BigDecimal amount; + + @Schema(description = "状态 | 0开启 1关闭") + private Integer status; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerStatusReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerStatusReqVO.java new file mode 100644 index 00000000..d1babf19 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerStatusReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 租赁客户新增/修改 Request VO") +@Data +public class RentalCustomerStatusReqVO { + + @Schema(description = "租赁客户表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "状态 | 0开启 1关闭") + private Integer status; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsCountReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsCountReqVO.java new file mode 100644 index 00000000..be1f259d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsCountReqVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 租赁物品数量 Request VO") +@Data +public class RentalItemsCountReqVO { + + @Schema(description = "租赁物品类型") + private Integer rentalItemsType; + + @Schema(description = "已租借数量") + private Integer number; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordPageReqVO.java new file mode 100644 index 00000000..003f17e2 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordPageReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租赁物品记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RentalItemsRecordPageReqVO extends PageParam { + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "租赁物品种类 | 字典值参考 system_rental_items_type") + private Integer rentalItemsType; + + @Schema(description = "类型 | 1租借 2归还") + private Integer type; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordRespVO.java new file mode 100644 index 00000000..227afce4 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租赁物品记录 Response VO") +@Data +public class RentalItemsRecordRespVO { + + @Schema(description = "租赁订单表单主键") + private Long id; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "租赁物品种类 | 字典值参考 system_rental_items_type") + private Integer rentalItemsType; + + @Schema(description = "租赁数量") + private Integer number; + + @Schema(description = "类型 | 1租借 2归还") + private Integer type; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordSaveReqVO.java new file mode 100644 index 00000000..75858ad2 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordSaveReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 租赁物品记录新增/修改 Request VO") +@Data +public class RentalItemsRecordSaveReqVO { + + @Schema(description = "租赁订单表单主键") + private Long id; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "订单编号不能为空") + private String orderNo; + + @Schema(description = "租赁物品种类 | 字典值参考 system_rental_items_type", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "租赁物品种类不能为空") + private Integer rentalItemsType; + + @Schema(description = "租赁数量", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "租赁数量不能为空") + private Integer number; + + @Schema(description = "类型 | 1租借 2归还", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "类型不能为空") + private Integer type; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java new file mode 100644 index 00000000..b5346fe7 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.order; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租赁订单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RentalOrderPageReqVO extends PageParam { + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "收款人") + private String recipient; + + @Schema(description = "客户编号") + private Long customerId; + + @Schema(description = "押金金额") + private Integer depositAmount; + + @Schema(description = "状态 | 1租赁中 2退款中 3已退") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java new file mode 100644 index 00000000..b4baa774 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租赁订单 Response VO") +@Data +public class RentalOrderRespVO { + + @Schema(description = "租赁订单表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "客户编号") + private Long customerId; + + @Schema(description = "客户名称") + private String customerName; + + @Schema(description = "客户开户行") + private String customerBankName; + + @Schema(description = "客户银行卡号") + private String customerBankNo; + + @Schema(description = "收款人") + private String recipient; + + @Schema(description = "押金金额") + private BigDecimal depositAmount; + + @Schema(description = "已收金额") + private BigDecimal receivedAmount; + + @Schema(description = "退款金额") + private BigDecimal refundAmount; + + @Schema(description = "扣款金额") + private BigDecimal chargebacksAmount; + + @Schema(description = "备注") + private String notes; + + @Schema(description = "状态 | 1租赁中 2退款中 3已退") + private Integer status; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "创建人姓名") + private String creatorName; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java new file mode 100644 index 00000000..93de6f0d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.order; + +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.List; + +@Schema(description = "管理后台 - 租赁订单新增/修改 Request VO") +@Data +public class RentalOrderSaveReqVO { + + @Schema(description = "租赁订单表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "客户编号不能为空") + private Long customerId; + + @Schema(description = "收款人") + private String recipient; + + @Schema(description = "押金金额", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "押金金额不能为空") + private BigDecimal depositAmount; + + @Schema(description = "扣款金额") + private BigDecimal chargebacksAmount; + + @Schema(description = "备注") + private String notes; + + @Schema(description = "状态 | 1租赁中 2退款中 3已退") + private Integer status; + + @Schema(description = "租赁物品记录") + private List itemsRecords; + + @Schema(description = "租赁订单押金记录") + private List depositRecords; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositAmountReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositAmountReqVO.java new file mode 100644 index 00000000..828b2df5 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositAmountReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 押金金额 Request VO") +@Data +public class RentalDepositAmountReqVO { + + @Schema(description = "已收金额") + private BigDecimal receivedAmount; + + @Schema(description = "退款金额") + private BigDecimal refundAmount; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordPageReqVO.java new file mode 100644 index 00000000..4d391fbd --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordPageReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租赁订单押金记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RentalDepositRecordPageReqVO extends PageParam { + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "支付方式 | 1支付宝 2微信 3银行卡") + private Integer paymentMethod; + + @Schema(description = "交易订单号") + private String transactionOrderNumber; + + @Schema(description = "收款/退款日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDate[] paymentDate; + + @Schema(description = "类型 | 1收款 2退款", example = "1") + private Integer type; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordRespVO.java new file mode 100644 index 00000000..7c04d37c --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordRespVO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 租赁订单押金记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class RentalDepositRecordRespVO { + + @Schema(description = "租赁订单押金记录表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("租赁订单押金记录表单主键") + private Long id; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("订单编号") + private String orderNo; + + @Schema(description = "支付方式 | 1支付宝 2微信 3银行卡", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("支付方式 | 1支付宝 2微信 3银行卡") + private Integer paymentMethod; + + @Schema(description = "交易订单号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("交易订单号") + private String transactionOrderNumber; + + @Schema(description = "银行卡号") + @ExcelProperty("银行卡号") + private String bankNo; + + @Schema(description = "客户银行卡号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("客户银行卡号") + private String customerBankNo; + + @Schema(description = "收款/退款金额", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("收款/退款金额") + private BigDecimal amount; + + @Schema(description = "收款/退款日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("收款/退款日期") + private LocalDate paymentDate; + + @Schema(description = "类型 | 1收款 2退款", example = "1") + @ExcelProperty("类型 | 1收款 2退款") + private Integer type; + + @Schema(description = "附件信息") + @ExcelProperty("附件信息") + private List fileItems; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java new file mode 100644 index 00000000..3584c892 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +@Schema(description = "管理后台 - 租赁订单押金记录新增/修改 Request VO") +@Data +public class RentalDepositRecordSaveReqVO { + + @Schema(description = "租赁订单押金记录表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "订单编号不能为空") + private String orderNo; + + @Schema(description = "支付方式 | 1支付宝 2微信 3银行卡", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "支付方式 | 1支付宝 2微信 3银行卡不能为空") + private Integer paymentMethod; + + @Schema(description = "交易订单号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "交易订单号不能为空") + private String transactionOrderNumber; + + @Schema(description = "银行卡号") + private String bankNo; + + @Schema(description = "客户银行卡号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "客户银行卡号不能为空") + private String customerBankNo; + + @Schema(description = "收款/退款金额", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收款/退款金额不能为空") + private BigDecimal amount; + + @Schema(description = "收款/退款日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收款/退款日期不能为空") + private LocalDate paymentDate; + + @Schema(description = "类型 | 1收款 2退款", example = "1") + private Integer type; + + @Schema(description = "附件信息") + private List fileItems; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java index 4b3c3ee4..8bdb56bb 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java @@ -181,6 +181,16 @@ public class UserController { return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap)); } + @PostMapping({"/list-by-deptIds"}) + @Operation(summary = "获取用户精简信息列表", description = "只包含被开启的用户,主要用于前端的下拉选项,无数据权限") + @DataPermission(enable = false) + public CommonResult> getAllUserList(@RequestBody List deptIds) { + List list = userService.getUserListByDepts(1, deptIds, CommonStatusEnum.ENABLE.getStatus()); + // 拼接数据 + Map deptMap = deptService.getDeptMap( + convertList(list, AdminUserDO::getDeptId)); + return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap)); + } @PostMapping({"/list-all"}) @Operation(summary = "获取用户精简信息列表", description = "只包含被开启的用户,主要用于前端的下拉选项,无数据权限") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/project/ProjectDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/project/ProjectDO.java new file mode 100644 index 00000000..bd8c91c0 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/project/ProjectDO.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.project; + +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.time.LocalDate; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 项目管理 DO + * + * @author 符溶馨 + */ +@TableName(value = "system_project", autoResultMap = true) +@KeySequence("system_project_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProjectDO extends BaseDO { + + /** + * 项目管理表单主键 + */ + @TableId + private Long id; + /** + * 项目编号 + */ + private String projectNo; + /** + * 项目类型 | 字典值参考system_project_type + */ + private Integer type; + /** + * 项目名称 + */ + private String name; + /** + * 责任部门 + */ + private Long responsibleDept; + /** + * 参与部门集合 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set participationDept; + /** + * 责任人用户编号 + */ + private Long directorUserId; + /** + * 项目开始时间 + */ + private LocalDate startDate; + /** + * 项目结束时间 + */ + private LocalDate endDate; + /** + * 是否长期 | 0否 1是 + */ + private Integer isLongTerm; + /** + * 项目预算 + */ + private Integer projectBudget; + /** + * 项目内容 + */ + private String content; + /** + * 项目人员用户编号集合 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set staff; + /** + * 项目额外属性 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map dynamicAttribute; + /** + * 项目状态 | 1 进行中 2已完成 + */ + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalCustomerDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalCustomerDO.java new file mode 100644 index 00000000..33e5e265 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalCustomerDO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.rental; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * 租赁客户 DO + * + * @author 符溶馨 + */ +@TableName("system_rental_customer") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RentalCustomerDO extends BaseDO { + + /** + * 租赁客户表单主键 + */ + @TableId + private Long id; + /** + * 客户名称 + */ + private String name; + /** + * 手机号 + */ + private String mobile; + /** + * 开户行 + */ + private String bankName; + /** + * 卡号 + */ + private String bankNo; + /** + * 剩余押金金额 + */ + private BigDecimal amount; + + /** + * 状态 0开启 1关闭 + */ + private Integer status; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalDepositRecordDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalDepositRecordDO.java new file mode 100644 index 00000000..3744c117 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalDepositRecordDO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.rental; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +/** + * 租赁订单押金记录 DO + * + * @author 符溶馨 + */ +@TableName(value = "system_rental_deposit_record", autoResultMap = true) +@KeySequence("system_rental_deposit_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RentalDepositRecordDO extends BaseDO { + + /** + * 租赁订单押金记录表单主键 + */ + @TableId + private Long id; + /** + * 订单编号 + */ + private String orderNo; + /** + * 支付方式 | 1支付宝 2微信 3银行卡 + */ + private Integer paymentMethod; + /** + * 交易订单号 + */ + private String transactionOrderNumber; + /** + * 银行卡号 + */ + private String bankNo; + /** + * 客户银行卡号 + */ + private String customerBankNo; + /** + * 收款/退款金额 + */ + private BigDecimal amount; + /** + * 收款/退款日期 + */ + private LocalDate paymentDate; + /** + * 类型 | 1收款 2退款 + */ + private Integer type; + /** + * 附件信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List fileItems; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalItemsRecordDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalItemsRecordDO.java new file mode 100644 index 00000000..d30adccf --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalItemsRecordDO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.rental; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 订单租赁物品记录 DO + * + * @author 符溶馨 + */ +@TableName("system_rental_items_record") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RentalItemsRecordDO extends BaseDO { + + /** + * 订单租赁物品记录表单主键 + */ + @TableId + private Long id; + /** + * 订单编号 + */ + private String orderNo; + /** + * 租赁物品种类 | 字典值参考 system_rental_items_type + */ + private Integer rentalItemsType; + /** + * 租赁数量 + */ + private Integer number; + /** + * 类型 | 1租借 2归还 + */ + private Integer type; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java new file mode 100644 index 00000000..08d415ae --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.rental; + +import lombok.*; + +import java.math.BigDecimal; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 租赁订单 DO + * + * @author 符溶馨 + */ +@TableName("system_rental_order") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RentalOrderDO extends BaseDO { + + /** + * 租赁订单表单主键 + */ + @TableId + private Long id; + /** + * 订单编号 + */ + private String orderNo; + /** + * 客户编号 + */ + private Long customerId; + /** + * 收款人 + */ + private String recipient; + /** + * 押金金额 + */ + private BigDecimal depositAmount; + /** + * 扣款金额 + */ + private BigDecimal chargebacksAmount; + /** + * 备注 + */ + private String notes; + /** + * 状态 | 1租赁中 2退款中 3已退 + */ + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java new file mode 100644 index 00000000..134f819b --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.dal.mysql.project; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 项目管理 Mapper + * + * @author 符溶馨 + */ +@Mapper +public interface ProjectMapper extends BaseMapperX { + + default PageResult selectPage(ProjectPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ProjectDO::getProjectNo, reqVO.getProjectNo()) + .eqIfPresent(ProjectDO::getType, reqVO.getType()) + .likeIfPresent(ProjectDO::getName, reqVO.getName()) + .eqIfPresent(ProjectDO::getResponsibleDept, reqVO.getResponsibleDept()) + .likeIfPresent(ProjectDO::getParticipationDept, reqVO.getParticipationDept()) + .eqIfPresent(ProjectDO::getDirectorUserId, reqVO.getDirectorUserId()) + .betweenIfPresent(ProjectDO::getStartDate, reqVO.getStartDate()) + .betweenIfPresent(ProjectDO::getEndDate, reqVO.getEndDate()) + .eqIfPresent(ProjectDO::getIsLongTerm, reqVO.getIsLongTerm()) + .eqIfPresent(ProjectDO::getStatus, reqVO.getStatus()) + .orderByDesc(ProjectDO::getId)); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalCustomerMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalCustomerMapper.java new file mode 100644 index 00000000..1b3b82c8 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalCustomerMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.dal.mysql.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 租赁客户 Mapper + * + * @author 符溶馨 + */ +@Mapper +public interface RentalCustomerMapper extends BaseMapperX { + + default PageResult selectPage(RentalCustomerPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(RentalCustomerDO::getName, reqVO.getName()) + .eqIfPresent(RentalCustomerDO::getMobile, reqVO.getMobile()) + .likeIfPresent(RentalCustomerDO::getBankName, reqVO.getBankName()) + .eqIfPresent(RentalCustomerDO::getBankNo, reqVO.getBankNo()) + .eqIfPresent(RentalCustomerDO::getAmount, reqVO.getAmount()) + .betweenIfPresent(RentalCustomerDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(RentalCustomerDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalDepositRecordMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalDepositRecordMapper.java new file mode 100644 index 00000000..5b0e7bea --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalDepositRecordMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.dal.mysql.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; + +/** + * 租赁订单押金记录 Mapper + * + * @author 符溶馨 + */ +@Mapper +public interface RentalDepositRecordMapper extends BaseMapperX { + + default PageResult selectPage(RentalDepositRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(RentalDepositRecordDO::getOrderNo, reqVO.getOrderNo()) + .eqIfPresent(RentalDepositRecordDO::getPaymentMethod, reqVO.getPaymentMethod()) + .eqIfPresent(RentalDepositRecordDO::getTransactionOrderNumber, reqVO.getTransactionOrderNumber()) + .betweenIfPresent(RentalDepositRecordDO::getPaymentDate, reqVO.getPaymentDate()) + .eqIfPresent(RentalDepositRecordDO::getType, reqVO.getType()) + .betweenIfPresent(RentalDepositRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(RentalDepositRecordDO::getCreateTime)); + } + + RentalDepositAmountReqVO selectAmount(@Param("orderNo") String orderNo, + @Param("isUpdate") Boolean isUpdate); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java new file mode 100644 index 00000000..76356d45 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.dal.mysql.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsCountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalItemsRecordDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; +import java.util.List; + +@Mapper +public interface RentalItemsRecordMapper extends BaseMapperX { + + default PageResult selectPage(RentalItemsRecordPageReqVO reqVO) { + + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(RentalItemsRecordDO::getOrderNo, reqVO.getOrderNo()) + .eqIfPresent(RentalItemsRecordDO::getRentalItemsType, reqVO.getRentalItemsType()) + .eqIfPresent(RentalItemsRecordDO::getType, reqVO.getType()) + .betweenIfPresent(RentalItemsRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(RentalItemsRecordDO::getCreateTime)); + } + + List selectRentalItemsCount(@Param("orderNo") String orderNo); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalOrderMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalOrderMapper.java new file mode 100644 index 00000000..bfc9cd2b --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalOrderMapper.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.dal.mysql.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; + +/** + * 租赁订单 Mapper + * + * @author 符溶馨 + */ +@Mapper +public interface RentalOrderMapper extends BaseMapperX { + + default PageResult selectPage(RentalOrderPageReqVO reqVO) { + + MPJLambdaWrapperX queryWrapper = new MPJLambdaWrapperX<>(); + queryWrapper.selectAll(RentalOrderDO.class); + queryWrapper.selectAs(RentalCustomerDO::getName, RentalOrderRespVO::getCustomerName); + queryWrapper.selectAs("SUM( CASE WHEN deposit.type = 1 THEN deposit.amount END )", RentalOrderRespVO::getReceivedAmount); + queryWrapper.selectAs("SUM( CASE WHEN deposit.type = 2 THEN deposit.amount END )", RentalOrderRespVO::getRefundAmount); + queryWrapper.selectAs(AdminUserDO::getNickname, RentalOrderRespVO::getCreatorName); + queryWrapper.leftJoin(RentalDepositRecordDO.class, "deposit", RentalDepositRecordDO::getOrderNo, RentalOrderDO::getOrderNo); + queryWrapper.leftJoin(AdminUserDO.class, AdminUserDO::getId, RentalOrderDO::getCreator); + queryWrapper.leftJoin(RentalCustomerDO.class, RentalCustomerDO::getId, RentalOrderDO::getCustomerId); + queryWrapper.eqIfPresent(RentalOrderDO::getOrderNo, reqVO.getOrderNo()) + .eqIfPresent(RentalOrderDO::getCustomerId, reqVO.getCustomerId()) + .eqIfPresent(RentalOrderDO::getDepositAmount, reqVO.getDepositAmount()) + .eqIfPresent(RentalOrderDO::getStatus, reqVO.getStatus()) + .likeIfPresent(RentalOrderDO::getRecipient, reqVO.getRecipient()) + .betweenIfPresent(RentalOrderDO::getCreateTime, reqVO.getCreateTime()) + .groupBy(RentalOrderDO::getOrderNo) + .orderByDesc(RentalOrderDO::getCreateTime); + + return selectJoinPage(reqVO, RentalOrderRespVO.class, queryWrapper); + } + + BigDecimal selectOrderAmount(@Param("orderNo") String orderNo); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java index fc6a6220..24ad2f37 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java @@ -98,4 +98,11 @@ public interface RedisKeyConstants { * VALUE 数据格式:String 模版信息 */ String SMS_TEMPLATE = "sms_template"; + + /** + * 租赁订单剩余押金金额的缓存 + * KEY 格式:rental_order_amount:{orderNo} + * VALUE 数据格式:String 剩余金额 + */ + String RENTAL_ORDER_AMOUNT = "rental_order_amount"; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java new file mode 100644 index 00000000..bf942b7d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.system.service.project; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; + +import javax.validation.Valid; + +/** + * 项目管理 Service 接口 + * + * @author 符溶馨 + */ +public interface ProjectService { + + /** + * 创建项目管理 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProject(@Valid ProjectSaveReqVO createReqVO); + + /** + * 更新项目管理 + * + * @param updateReqVO 更新信息 + */ + void updateProject(@Valid ProjectSaveReqVO updateReqVO); + + /** + * 删除项目管理 + * + * @param id 编号 + */ + void deleteProject(Long id); + + /** + * 获得项目管理 + * + * @param id 编号 + * @return 项目管理 + */ + ProjectDO getProject(Long id); + + /** + * 获得项目管理分页 + * + * @param pageReqVO 分页查询 + * @return 项目管理分页 + */ + PageResult getProjectPage(ProjectPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java new file mode 100644 index 00000000..faf15d46 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.system.service.project; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; +import cn.iocoder.yudao.module.system.dal.mysql.project.ProjectMapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS; + +/** + * 项目管理 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +public class ProjectServiceImpl implements ProjectService { + + @Resource + private ProjectMapper projectMapper; + + @Override + public Long createProject(ProjectSaveReqVO createReqVO) { + // 插入 + ProjectDO project = BeanUtils.toBean(createReqVO, ProjectDO.class); + project.setProjectNo(IdWorker.getIdStr()); + projectMapper.insert(project); + // 返回 + return project.getId(); + } + + @Override + public void updateProject(ProjectSaveReqVO updateReqVO) { + // 校验存在 + validateProjectExists(updateReqVO.getId()); + // 更新 + ProjectDO updateObj = BeanUtils.toBean(updateReqVO, ProjectDO.class); + projectMapper.updateById(updateObj); + } + + @Override + public void deleteProject(Long id) { + // 校验存在 + validateProjectExists(id); + // 删除 + projectMapper.deleteById(id); + } + + private void validateProjectExists(Long id) { + if (projectMapper.selectById(id) == null) { + throw exception(PROJECT_NOT_EXISTS); + } + } + + @Override + public ProjectDO getProject(Long id) { + return projectMapper.selectById(id); + } + + @Override + public PageResult getProjectPage(ProjectPageReqVO pageReqVO) { + return projectMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerService.java new file mode 100644 index 00000000..c49cb2b5 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerService.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerStatusReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 租赁客户 Service 接口 + * + * @author 符溶馨 + */ +public interface RentalCustomerService { + + /** + * 创建租赁客户 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createRentalCustomer(@Valid RentalCustomerSaveReqVO createReqVO); + + /** + * 更新租赁客户 + * + * @param updateReqVO 更新信息 + */ + void updateRentalCustomer(@Valid RentalCustomerSaveReqVO updateReqVO); + + /** + * 更新租赁客户状态 + * @param updateReqVO 更新信息 + */ + void updateRentalCustomerStatus(RentalCustomerStatusReqVO updateReqVO); + + /** + * 删除租赁客户 + * + * @param id 编号 + */ + void deleteRentalCustomer(Long id); + + /** + * 获得租赁客户 + * + * @param id 编号 + * @return 租赁客户 + */ + RentalCustomerDO getRentalCustomer(Long id); + + /** + * 获得租赁客户分页 + * + * @param pageReqVO 分页查询 + * @return 租赁客户分页 + */ + PageResult getRentalCustomerPage(RentalCustomerPageReqVO pageReqVO); + + /** + * 获得租赁客户列表 + * @return 租赁客户列表 + */ + List getRentalCustomerList(); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerServiceImpl.java new file mode 100644 index 00000000..071a1b2c --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerServiceImpl.java @@ -0,0 +1,91 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerStatusReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalCustomerMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_CUSTOMER_NOT_EXISTS; + +/** + * 租赁客户 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +public class RentalCustomerServiceImpl implements RentalCustomerService { + + @Resource + private RentalCustomerMapper rentalCustomerMapper; + + @Override + public Long createRentalCustomer(RentalCustomerSaveReqVO createReqVO) { + // 插入 + RentalCustomerDO rentalCustomer = BeanUtils.toBean(createReqVO, RentalCustomerDO.class); + rentalCustomer.setStatus(CommonStatusEnum.ENABLE.getStatus()); + rentalCustomerMapper.insert(rentalCustomer); + // 返回 + return rentalCustomer.getId(); + } + + @Override + public void updateRentalCustomer(RentalCustomerSaveReqVO updateReqVO) { + // 校验存在 + validateRentalCustomerExists(updateReqVO.getId()); + // 更新 + RentalCustomerDO updateObj = BeanUtils.toBean(updateReqVO, RentalCustomerDO.class); + rentalCustomerMapper.updateById(updateObj); + } + + @Override + public void updateRentalCustomerStatus(RentalCustomerStatusReqVO updateReqVO) { + // 校验存在 + validateRentalCustomerExists(updateReqVO.getId()); + // 更新 + RentalCustomerDO updateObj = BeanUtils.toBean(updateReqVO, RentalCustomerDO.class); + rentalCustomerMapper.updateById(updateObj); + } + + @Override + public void deleteRentalCustomer(Long id) { + // 校验存在 + validateRentalCustomerExists(id); + // 删除 + rentalCustomerMapper.deleteById(id); + } + + private void validateRentalCustomerExists(Long id) { + if (rentalCustomerMapper.selectById(id) == null) { + throw exception(RENTAL_CUSTOMER_NOT_EXISTS); + } + } + + @Override + public RentalCustomerDO getRentalCustomer(Long id) { + return rentalCustomerMapper.selectById(id); + } + + @Override + public PageResult getRentalCustomerPage(RentalCustomerPageReqVO pageReqVO) { + return rentalCustomerMapper.selectPage(pageReqVO); + } + + @Override + public List getRentalCustomerList() { + return rentalCustomerMapper.selectList(RentalCustomerDO::getStatus, CommonStatusEnum.ENABLE.getStatus()); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordService.java new file mode 100644 index 00000000..cb8a66ec --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordService.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.List; + +/** + * 租赁订单押金记录 Service 接口 + * + * @author 符溶馨 + */ +public interface RentalDepositRecordService { + + /** + * 创建租赁订单押金记录 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createRentalDepositRecord(@Valid RentalDepositRecordSaveReqVO createReqVO); + + /** + * 批量创建租赁订单押金记录 + * + * @param createReqVO 创建信息 + */ + void createRentalDepositRecordBatch(@Valid List createReqVO); + + /** + * 更新租赁订单押金记录 + * + * @param updateReqVO 更新信息 + */ + void updateRentalDepositRecord(@Valid RentalDepositRecordSaveReqVO updateReqVO); + + /** + * 获得租赁订单押金记录 + * + * @param id 编号 + * @return 租赁订单押金记录 + */ + RentalDepositRecordDO getRentalDepositRecord(Long id); + + /** + * 获得租赁订单押金记录分页 + * + * @param pageReqVO 分页查询 + * @return 租赁订单押金记录分页 + */ + PageResult getRentalDepositRecordPage(RentalDepositRecordPageReqVO pageReqVO); + + /** + * 获得指定订单的已收取的押金金额 + * @param orderNo 订单编号 + * @return 数量 + */ + RentalDepositAmountReqVO getRentalDepositRecordAmount(String orderNo, Boolean isUpdate); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java new file mode 100644 index 00000000..9ae839bd --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java @@ -0,0 +1,129 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalDepositRecordMapper; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.List; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 租赁订单押金记录 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +public class RentalDepositRecordServiceImpl implements RentalDepositRecordService { + + @Resource + private RentalDepositRecordMapper rentalDepositRecordMapper; + + @Resource + @Lazy + private RentalOrderService rentalOrderService; + + @Resource + private FileApi fileApi; + + @Override + public Long createRentalDepositRecord(RentalDepositRecordSaveReqVO createReqVO) { + + // 获取当前订单的 剩余押金金额 + BigDecimal depositAmount = rentalOrderService.getOrderAmount(createReqVO.getOrderNo()); + + // 获取当前订单的金额 + RentalDepositAmountReqVO reqVO = getRentalDepositRecordAmount(createReqVO.getOrderNo(), true); + // 已收金额 - 退款金额 + BigDecimal amount = reqVO.getReceivedAmount().subtract(reqVO.getRefundAmount()); + + switch (createReqVO.getType()) { + case 1: + // 押金收款 + // 判断实际已收的金额 + 本次收款金额 大于 当前订单的剩余押金金额时 + if (amount.add(createReqVO.getAmount()).compareTo(depositAmount) > 0) { + throw exception(RENTAL_RECEIVED_AMOUNT_EXCESS); + } + break; + case 2: + // 押金退款 + // 判断当前退款金额 大于 实际已收的金额时 + if (amount.compareTo(createReqVO.getAmount()) < 0) { + throw exception(RENTAL_REFUND_AMOUNT_EXCESS); + } + break; + } + + // 插入 + RentalDepositRecordDO rentalDepositRecord = BeanUtils.toBean(createReqVO, RentalDepositRecordDO.class); + rentalDepositRecordMapper.insert(rentalDepositRecord); + + // 更新交易凭证附件 业务编号 + UpdateBusinessFile(rentalDepositRecord); + // 返回 + return rentalDepositRecord.getId(); + } + + @Override + public void createRentalDepositRecordBatch(List createReqVO) { + // 插入 + List rentalDepositRecord = BeanUtils.toBean(createReqVO, RentalDepositRecordDO.class); + rentalDepositRecordMapper.insertBatch(rentalDepositRecord); + + for (RentalDepositRecordDO record : rentalDepositRecord) { + // 更新交易凭证附件 业务编号 + UpdateBusinessFile(record); + } + } + + private void UpdateBusinessFile(RentalDepositRecordDO updateReqVO) { + + List urls = updateReqVO.getFileItems().stream().map(UploadUserFile::getUrl).collect(Collectors.toList()); + fileApi.updateBusinessFile(urls, updateReqVO.getId().toString()); + } + + @Override + public void updateRentalDepositRecord(RentalDepositRecordSaveReqVO updateReqVO) { + // 校验存在 + validateRentalDepositRecordExists(updateReqVO.getId()); + // 更新 + RentalDepositRecordDO updateObj = BeanUtils.toBean(updateReqVO, RentalDepositRecordDO.class); + rentalDepositRecordMapper.updateById(updateObj); + } + + private void validateRentalDepositRecordExists(Long id) { + if (rentalDepositRecordMapper.selectById(id) == null) { + throw exception(RENTAL_DEPOSIT_RECORD_NOT_EXISTS); + } + } + + @Override + public RentalDepositRecordDO getRentalDepositRecord(Long id) { + return rentalDepositRecordMapper.selectById(id); + } + + @Override + public PageResult getRentalDepositRecordPage(RentalDepositRecordPageReqVO pageReqVO) { + return rentalDepositRecordMapper.selectPage(pageReqVO); + } + + @Override + public RentalDepositAmountReqVO getRentalDepositRecordAmount(String orderNo, Boolean isUpdate) { + return rentalDepositRecordMapper.selectAmount(orderNo, isUpdate); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java new file mode 100644 index 00000000..53253125 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsCountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalItemsRecordDO; +import io.swagger.v3.oas.models.security.SecurityScheme; + +import javax.validation.Valid; +import java.util.List; + +/** + * 租赁物品记录 Service 接口 + * + * @author 符溶馨 + */ +public interface RentalItemsRecordService { + + /** + * 创建租赁物品记录 + * @param createReqVO 创建信息 + */ + Long createRentalItemsRecord(@Valid RentalItemsRecordSaveReqVO createReqVO); + + /** + * 创建租赁物品记录 + * @param createReqVO 创建信息 + */ + void createRentalItemsRecordBath(@Valid List createReqVO); + + /** + * 更新租赁物品记录 + * @param updateReqVO 更新信息 + */ + void updateRentalItemsRecord(@Valid RentalItemsRecordSaveReqVO updateReqVO); + + /** + * 查询租赁物品记录 + * @param id id + * @return 租赁物品记录 + */ + RentalItemsRecordDO getRentalItemsRecord(Long id); + + /** + * 分页查询租赁物品记录 + * @param pageReqVO 分页参数 + * @return 租赁物品记录列表 + */ + PageResult getRentalItemsRecordPage(RentalItemsRecordPageReqVO pageReqVO); + + /** + * 获取指定订单指定类型的租赁物品的剩余数量 + * @param orderNo 订单编号 + * @return 剩余数量 + */ + List getRentalItemsCount(String orderNo); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java new file mode 100644 index 00000000..3301cd6d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsCountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalItemsRecordDO; +import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalItemsRecordMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_ITEMS_NUMBER_EXCESS; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_ITEMS_RECORD_NOT_EXISTS; + +/** + * 租赁物品记录 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +@Slf4j +public class RentalItemsRecordServiceImpl implements RentalItemsRecordService{ + + @Resource + private RentalItemsRecordMapper rentalItemsRecordMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createRentalItemsRecord(RentalItemsRecordSaveReqVO createReqVO) { + + // 获取订单剩余租借数量 使用悲观锁 + List reqVOS = getRentalItemsCount(createReqVO.getOrderNo()); + Map countMap = convertMap(reqVOS, RentalItemsCountReqVO::getRentalItemsType); + + // 判断租借类型为归还时,检验归还数量是否大于剩余数量 + if (createReqVO.getType() == 2 && countMap.get(createReqVO.getRentalItemsType()).getNumber() < createReqVO.getNumber()) { + throw exception(RENTAL_ITEMS_NUMBER_EXCESS); + } + + RentalItemsRecordDO createDO = BeanUtils.toBean(createReqVO, RentalItemsRecordDO.class); + rentalItemsRecordMapper.insert(createDO); + + return createDO.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void createRentalItemsRecordBath(List createReqVO) { + + // 获取订单剩余租借数量 使用悲观锁 + List reqVOS = getRentalItemsCount(createReqVO.get(0).getOrderNo()); + Map countMap = convertMap(reqVOS, RentalItemsCountReqVO::getRentalItemsType); + + for (RentalItemsRecordSaveReqVO vo : createReqVO) { + + // 判断租借类型为归还时,检验归还数量是否大于剩余数量 + if (vo.getType() == 2) { + + if (countMap.get(vo.getRentalItemsType()) != null && + countMap.get(vo.getRentalItemsType()).getNumber() < vo.getNumber()) { + throw exception(RENTAL_ITEMS_NUMBER_EXCESS); + } + } + } + + List createReq = BeanUtils.toBean(createReqVO, RentalItemsRecordDO.class); + rentalItemsRecordMapper.insertBatch(createReq); + } + + @Override + public void updateRentalItemsRecord(RentalItemsRecordSaveReqVO updateReqVO) { + + // 校验存在 + validateRentalItemsRecordExists(updateReqVO.getId()); + + RentalItemsRecordDO updateObj = BeanUtils.toBean(updateReqVO, RentalItemsRecordDO.class); + rentalItemsRecordMapper.updateById(updateObj); + } + + @Override + public RentalItemsRecordDO getRentalItemsRecord(Long id) { + return rentalItemsRecordMapper.selectById(id); + } + + @Override + public PageResult getRentalItemsRecordPage(RentalItemsRecordPageReqVO pageReqVO) { + return rentalItemsRecordMapper.selectPage(pageReqVO); + } + + @Override + public List getRentalItemsCount(String orderNo) { + + return rentalItemsRecordMapper.selectRentalItemsCount(orderNo); + } + + private void validateRentalItemsRecordExists(Long id) { + if (rentalItemsRecordMapper.selectById(id) == null) { + throw exception(RENTAL_ITEMS_RECORD_NOT_EXISTS); + } + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java new file mode 100644 index 00000000..c42cec47 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; + +import javax.validation.Valid; +import java.math.BigDecimal; + +/** + * 租赁订单 Service 接口 + * + * @author 符溶馨 + */ +public interface RentalOrderService { + + /** + * 创建租赁订单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createRentalOrder(@Valid RentalOrderSaveReqVO createReqVO); + + /** + * 更新租赁订单 + * + * @param updateReqVO 更新信息 + */ + BigDecimal updateRentalOrder(@Valid RentalOrderSaveReqVO updateReqVO); + + /** + * 删除租赁订单 + * + * @param id 编号 + */ + void deleteRentalOrder(Long id); + + /** + * 获得租赁订单 + * + * @param id 编号 + * @return 租赁订单 + */ + RentalOrderDO getRentalOrder(Long id); + + /** + * 获得租赁订单分页 + * + * @param pageReqVO 分页查询 + * @return 租赁订单分页 + */ + PageResult getRentalOrderPage(RentalOrderPageReqVO pageReqVO); + + /** + * 获取订单的剩余押金金额(押金金额-扣款金额) + * @param orderNo 订单编号 + * @return 剩余押金金额 + */ + BigDecimal getOrderAmount(String orderNo); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java new file mode 100644 index 00000000..221fc2ab --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java @@ -0,0 +1,148 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; +import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalOrderMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_ORDER_NOT_EXISTS; + +/** + * 租赁订单 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +@Slf4j +public class RentalOrderServiceImpl implements RentalOrderService { + + @Resource + private RentalOrderMapper rentalOrderMapper; + + @Resource + @Lazy + private RentalItemsRecordService rentalItemsRecordService; + + @Resource + @Lazy + private RentalDepositRecordService rentalDepositRecordService; + + @Resource + private RedissonClient redissonClient; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + @Override + public Long createRentalOrder(RentalOrderSaveReqVO createReqVO) { + // 新增订单DO + RentalOrderDO rentalOrder = BeanUtils.toBean(createReqVO, RentalOrderDO.class); + + // 获取当前日期 + String now = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + // 获取分布式锁 + String LOCK_KEY = "lock:rental:order:create"; + RLock lock = redissonClient.getLock(LOCK_KEY); + try { + lock.lock(); + // redis 获取当天订单号 + String no = stringRedisTemplate.opsForValue().get(now); + if (no != null) { + no = "ZL" + now + String.format("%03d", Integer.parseInt(no) + 1); + // redis 缓存订单号 + stringRedisTemplate.opsForValue().increment(now, 1); + }else { + no = "ZL" + now + String.format("%03d", 1); + // redis 缓存订单号 + stringRedisTemplate.opsForValue().set(now, "1", 1, TimeUnit.DAYS); + } + // 设置订单编号 + rentalOrder.setOrderNo(no); + createReqVO.getDepositRecords().forEach(item -> item.setOrderNo(rentalOrder.getOrderNo())); + createReqVO.getItemsRecords().forEach(item -> item.setOrderNo(rentalOrder.getOrderNo())); + } catch (Exception ex) { + log.error("[messageResend][执行异常]", ex); + } finally { + lock.unlock(); + } + + // 插入订单 + rentalOrderMapper.insert(rentalOrder); + + // 同步插入租赁物品记录 + rentalItemsRecordService.createRentalItemsRecordBath(createReqVO.getItemsRecords()); + if (CollectionUtil.isNotEmpty(createReqVO.getDepositRecords())) { + // 同步插入租赁押金记录 + rentalDepositRecordService.createRentalDepositRecordBatch(createReqVO.getDepositRecords()); + } + + // 返回 + return rentalOrder.getId(); + } + + @Override + @CachePut(value = RedisKeyConstants.RENTAL_ORDER_AMOUNT, key = "#updateReqVO.orderNo", condition = "#updateReqVO.status == 1") + public BigDecimal updateRentalOrder(RentalOrderSaveReqVO updateReqVO) { + // 校验存在 + validateRentalOrderExists(updateReqVO.getId()); + // 更新 + RentalOrderDO updateObj = BeanUtils.toBean(updateReqVO, RentalOrderDO.class); + rentalOrderMapper.updateById(updateObj); + + return updateObj.getDepositAmount().subtract(updateObj.getChargebacksAmount() == null ? BigDecimal.ZERO : updateObj.getChargebacksAmount()); + } + + @Override + public void deleteRentalOrder(Long id) { + // 校验存在 + validateRentalOrderExists(id); + // 删除 + rentalOrderMapper.deleteById(id); + } + + private void validateRentalOrderExists(Long id) { + if (rentalOrderMapper.selectById(id) == null) { + throw exception(RENTAL_ORDER_NOT_EXISTS); + } + } + + @Override + public RentalOrderDO getRentalOrder(Long id) { + return rentalOrderMapper.selectById(id); + } + + @Override + public PageResult getRentalOrderPage(RentalOrderPageReqVO pageReqVO) { + return rentalOrderMapper.selectPage(pageReqVO); + } + + @Override + @Cacheable(value = RedisKeyConstants.RENTAL_ORDER_AMOUNT, key = "#orderNo", unless = "#result == null") + public BigDecimal getOrderAmount(String orderNo) { + return rentalOrderMapper.selectOrderAmount(orderNo); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java index f4585e65..a80f5c96 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java @@ -413,4 +413,13 @@ public interface AdminUserService { * @param entryDate */ void updateUserEntryDate(Long id, LocalDateTime entryDate); + + /** + * 获取指定部门下的用户信息 + * @param userType 用户类型 + * @param deptIds 部门列表 + * @param status 用户状态 + * @return 用户列表 + */ + List getUserListByDepts(Integer userType, List deptIds, Integer status); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index 4a95314d..ffcf766f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -803,4 +803,12 @@ public class AdminUserServiceImpl implements AdminUserService { public void updateUserEntryDate(Long id, LocalDateTime entryDate) { userMapper.updateById(new AdminUserDO().setId(id).setEntryDate(entryDate)); } + + @Override + public List getUserListByDepts(Integer userType, List deptIds, Integer status) { + return userMapper.selectList(new LambdaQueryWrapperX() + .eqIfPresent(AdminUserDO::getUserType, userType) + .eqIfPresent(AdminUserDO::getStatus, status) + .inIfPresent(AdminUserDO::getDeptId, deptIds)); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalDepositRecordMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalDepositRecordMapper.xml new file mode 100644 index 00000000..7d657777 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalDepositRecordMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml new file mode 100644 index 00000000..0abb1b9b --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalOrderMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalOrderMapper.xml new file mode 100644 index 00000000..b75b1cde --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalOrderMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + From b224956b67de2c62d69f72c83955eeedcee8a145 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Fri, 15 Nov 2024 12:51:37 +0800 Subject: [PATCH 06/18] =?UTF-8?q?refactor(bpm):=20=E4=BC=98=E5=8C=96?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E5=AE=9E=E4=BE=8B=E6=9C=8D=E5=8A=A1=E5=92=8C?= =?UTF-8?q?=E6=B5=81=E7=A8=8B=E6=8A=84=E9=80=81=20mapper-=20=E5=B0=86=20Bp?= =?UTF-8?q?mProcessCcMapper=20=E4=B8=AD=E7=9A=84=20eqIfPresent=20=E6=94=B9?= =?UTF-8?q?=E4=B8=BA=20likeIfPresent=EF=BC=8C=E6=8F=90=E9=AB=98=E6=9F=A5?= =?UTF-8?q?=E8=AF=A2=E7=81=B5=E6=B4=BB=E6=80=A7-=20=E4=BC=98=E5=8C=96=20Bp?= =?UTF-8?q?mProcessInstanceServiceImpl=20=E4=B8=AD=E7=9A=84=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E7=BB=84=E5=92=8C=E6=8A=84=E9=80=81=E9=80=BB=E8=BE=91?= =?UTF-8?q?=20-=20=E6=B7=BB=E5=8A=A0=E7=A9=BA=E9=9B=86=E5=90=88=E5=88=A4?= =?UTF-8?q?=E6=96=AD=EF=BC=8C=E9=81=BF=E5=85=8D=E4=B8=8D=E5=BF=85=E8=A6=81?= =?UTF-8?q?=E7=9A=84=E6=93=8D=E4=BD=9C=20-=20=E8=B0=83=E6=95=B4=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E6=A0=BC=E5=BC=8F=EF=BC=8C=E6=8F=90=E9=AB=98=E5=8F=AF?= =?UTF-8?q?=E8=AF=BB=E6=80=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../module/bpm/dal/mysql/definition/BpmProcessCcMapper.java | 2 +- .../module/bpm/service/task/BpmProcessInstanceServiceImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessCcMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessCcMapper.java index f12543e0..94090084 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessCcMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/definition/BpmProcessCcMapper.java @@ -20,7 +20,7 @@ public interface BpmProcessCcMapper extends BaseMapperX { return selectPage(reqVO, new LambdaQueryWrapperX() .likeIfPresent(BpmProcessCcDO::getName, reqVO.getName()) .likeIfPresent(BpmProcessCcDO::getUserGroupId, reqVO.getUserGroupId()) - .eqIfPresent(BpmProcessCcDO::getCompanyDeptId, reqVO.getCompanyDeptId()) + .likeIfPresent(BpmProcessCcDO::getCompanyDeptId, reqVO.getCompanyDeptId()) .eqIfPresent(BpmProcessCcDO::getStatus, reqVO.getStatus()) .orderByDesc(BpmProcessCcDO::getId)); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 75905129..153de2c9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.DynamicMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessCcService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOACashService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); // 查询流程变量 List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(paramMap)); // 创建流程后,添加抄送人 processCCToUsers(instance); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) @DataPermission(enable = false) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(id) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @param * @return */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; } catch (Exception exception) { exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId(); List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setCcids(ccIds) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO(); String key = reqVO.getKey(); //流程标识 String processInstanceId = reqVO.getId(); //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId); bpmProcessInstancePrintDataRespVO.setKey(key); BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId); Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.DynamicMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessCcService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOACashService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); // 查询流程变量 List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(paramMap)); // 创建流程后,添加抄送人 processCCToUsers(instance); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) @DataPermission(enable = false) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(id) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @param * @return */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; } catch (Exception exception) { exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId(); List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setCcids(ccIds) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } } @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO(); String key = reqVO.getKey(); //流程标识 String processInstanceId = reqVO.getId(); //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId); bpmProcessInstancePrintDataRespVO.setKey(key); BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId); Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file From f5ff97b375574ba6e7e8e4c0047d0dea2d2ca942 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sun, 17 Nov 2024 17:20:47 +0800 Subject: [PATCH 07/18] =?UTF-8?q?feat(bpm):=20=E5=88=86=E7=A6=BB=E5=A4=87?= =?UTF-8?q?=E7=94=A8=E9=87=91=E9=87=91=E9=A2=9D=E4=B8=8E=E5=89=A9=E4=BD=99?= =?UTF-8?q?=E9=87=91=E9=A2=9D=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在 BpmOACashRespVO 和 BpmOAReimbursementRespVO 中添加 remainingAmount 字段 - 修改 BpmProcessInstanceServiceImpl 中的逻辑,分别设置 amount 和 remainingAmount - 此修改提高了数据的准确性和可靠性,避免了之前金额混淆的问题 --- .../bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java | 3 +++ .../admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java | 5 ++++- .../bpm/service/task/BpmProcessInstanceServiceImpl.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java index bb9ac6c2..9228d0ae 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/cash/BpmOACashRespVO.java @@ -46,6 +46,9 @@ public class BpmOACashRespVO extends BpmOABaseRespVO { @Schema(description = "备用金金额") private BigDecimal amount; + @Schema(description = "备用金剩余金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private BigDecimal remainingAmount; + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) private List fileItems; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java index 0a9f68af..73d29593 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/reimbursement/BpmOAReimbursementRespVO.java @@ -44,7 +44,10 @@ public class BpmOAReimbursementRespVO extends BpmOABaseRespVO { private BigDecimal reimbursementType ; @Schema(description = "备用金金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) - private BigDecimal amount ; + private BigDecimal amount; + + @Schema(description = "备用金剩余金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private BigDecimal remainingAmount; @Schema(description = "备用金ID") private Long imprestId; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java index 153de2c9..fcfbf2b3 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java @@ -1 +1 @@ -package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.DynamicMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessCcService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOACashService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); // 查询流程变量 List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(paramMap)); // 创建流程后,添加抄送人 processCCToUsers(instance); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) @DataPermission(enable = false) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(id) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @param * @return */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; } catch (Exception exception) { exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId(); List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setCcids(ccIds) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } } @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO(); String key = reqVO.getKey(); //流程标识 String processInstanceId = reqVO.getId(); //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId); bpmProcessInstancePrintDataRespVO.setKey(key); BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId); Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file +package cn.iocoder.yudao.module.bpm.service.task; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.core.lang.Assert; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.date.DateUtils; import cn.iocoder.yudao.framework.common.util.number.NumberUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.flowable.core.util.FlowableUtils; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.cash.BpmOACashRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOACashPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmOAReimbursementPrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.print.BpmProcessInstancePrintDataRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.reimbursement.BpmOAReimbursementRespVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.instance.*; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskApproveReqVO; import cn.iocoder.yudao.module.bpm.controller.admin.task.vo.task.BpmTaskRespVO; import cn.iocoder.yudao.module.bpm.convert.task.BpmProcessInstanceConvert; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessCcDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmProcessDefinitionExtDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmTaskAssignRuleDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.definition.BpmUserGroupDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOACashDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAImprestDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReimbursementDO; import cn.iocoder.yudao.module.bpm.dal.dataobject.task.BpmProcessInstanceExtDO; import cn.iocoder.yudao.module.bpm.dal.mysql.DynamicMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.definition.BpmTaskAssignRuleMapper; import cn.iocoder.yudao.module.bpm.dal.mysql.task.BpmProcessInstanceExtMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmConstants; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceDeleteReasonEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceStatusEnum; import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventPublisher; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessCcService; import cn.iocoder.yudao.module.bpm.service.definition.BpmProcessDefinitionService; import cn.iocoder.yudao.module.bpm.service.definition.BpmUserGroupService; import cn.iocoder.yudao.module.bpm.service.message.BpmMessageService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOACashService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAImprestService; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProcureServiceImpl; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReimbursementService; import cn.iocoder.yudao.module.bpm.service.task.dto.ProcessInstanceVariablesDTO; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.api.dept.DeptApi; import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; import cn.iocoder.yudao.module.system.api.permission.PermissionApi; import cn.iocoder.yudao.module.system.api.permission.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.module.system.api.user.AdminUserApi; import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import jodd.util.StringUtil; import lombok.extern.slf4j.Slf4j; import org.flowable.engine.HistoryService; import org.flowable.engine.RuntimeService; import org.flowable.engine.TaskService; import org.flowable.engine.delegate.event.FlowableCancelledEvent; import org.flowable.engine.history.HistoricProcessInstance; import org.flowable.engine.repository.ProcessDefinition; import org.flowable.engine.runtime.ProcessInstance; import org.flowable.task.api.Task; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import javax.validation.Valid; import java.lang.reflect.Field; import java.text.DecimalFormat; import java.time.LocalDateTime; import java.time.temporal.ChronoUnit; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.*; /** * 流程实例 Service 实现类 *

* ProcessDefinition & ProcessInstance & Execution & Task 的关系: * 1. *

* HistoricProcessInstance & ProcessInstance 的关系: * 1. *

* 简单来说,前者 = 历史 + 运行中的流程实例,后者仅是运行中的流程实例 */ @Service @Validated @Slf4j public class BpmProcessInstanceServiceImpl implements BpmProcessInstanceService { @Resource private TaskService engineTaskService; @Resource private BpmTaskAssignRuleMapper taskRuleMapper; @Resource private BpmUserGroupService userGroupService; @Resource private RuntimeService runtimeService; @Resource private BpmProcessInstanceExtMapper processInstanceExtMapper; @Resource @Lazy // 解决循环依赖 private BpmTaskService taskService; @Resource private BpmProcessDefinitionService processDefinitionService; @Resource private HistoryService historyService; @Resource private AdminUserApi adminUserApi; @Resource private DeptApi deptApi; @Resource private BpmProcessInstanceResultEventPublisher processInstanceResultEventPublisher; @Resource @Lazy // 解决循环依赖 private BpmMessageService messageService; @Resource private ConfigApi configApi; @Resource private DynamicMapper dynamicMapper ; @Resource private BpmProcessCcService processCcService; @Override public ProcessInstance getProcessInstance(String id) { return runtimeService.createProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getProcessInstances(Set ids) { return runtimeService.createProcessInstanceQuery().processInstanceIds(ids).list(); } public String transform(String input) { if(StringUtil.isNotEmpty(input)) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { result.append(keyValue[1]).append(","); } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } } return ""; } public String replaceValues(String input, Map map) { String[] parts = input.split(","); StringBuilder result = new StringBuilder(); for (String part : parts) { String[] keyValue = part.split(":"); if (keyValue.length > 1) { String key = keyValue[1].trim(); // 去除可能的空格 if (map.containsKey(key)) { Object value = map.get(key); String stringValue = (value != null) ? value.toString() : ""; // 将值转换为字符串 result.append(keyValue[0].trim()).append(":").append(stringValue).append(","); } else { //result.append(part).append(","); } } } if (result.length() > 0) { return result.substring(0, result.length() - 1); } return ""; } @Override @TenantIgnore public PageResult getMyProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectPage(userId, pageReqVO); List bpmProcessInstanceExtDOList = pageResult.getList() ; for (int i = 0; i < bpmProcessInstanceExtDOList.size() ; i++) { BpmProcessInstanceExtDO bpmProcessInstanceExtDO = bpmProcessInstanceExtDOList.get(i) ; String input = bpmProcessInstanceExtDO.getFieldNames() ; if(StringUtil.isNotEmpty(input)) { String sql = "SELECT " + transform(bpmProcessInstanceExtDO.getFieldNames()) + " FROM " + bpmProcessInstanceExtDO.getTableName() + " WHERE id=" + bpmProcessInstanceExtDO.getBusinessKey(); log.info(sql); Map map = dynamicMapper.selectListByTableName(sql) ; String detailInfo = replaceValues(bpmProcessInstanceExtDO.getFieldNames(),map) ; bpmProcessInstanceExtDO.setDetailInfo(detailInfo); } } if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); // 获得 User Map Map userMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, userMap); } @Override @Transactional(rollbackFor = Exception.class) public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqVO createReqVO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition(createReqVO.getProcessDefinitionId()); // 发起流程 return createProcessInstance0(userId, definition, createReqVO.getVariables(), null); } @Override public String createProcessInstance(Long userId, @Valid BpmProcessInstanceCreateReqDTO createReqDTO) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getActiveProcessDefinition(createReqDTO.getProcessDefinitionKey()); // 发起流程 return createProcessInstance0(userId, definition, createReqDTO.getVariables(), createReqDTO.getBusinessKey()); } @Override public BpmProcessInstanceRespVO getProcessInstanceVO(String id) { // 获得流程实例 HistoricProcessInstance processInstance = getHistoricProcessInstance(id); if (processInstance == null) { return null; } BpmProcessInstanceExtDO processInstanceExt = processInstanceExtMapper.selectByProcessInstanceId(id); Assert.notNull(processInstanceExt, "流程实例拓展({}) 不存在", id); // 获得流程定义 ProcessDefinition processDefinition = processDefinitionService .getProcessDefinition(processInstance.getProcessDefinitionId()); Assert.notNull(processDefinition, "流程定义({}) 不存在", processInstance.getProcessDefinitionId()); BpmProcessDefinitionExtDO processDefinitionExt = processDefinitionService.getProcessDefinitionExt( processInstance.getProcessDefinitionId()); Assert.notNull(processDefinitionExt, "流程定义拓展({}) 不存在", id); String bpmnXml = processDefinitionService.getProcessDefinitionBpmnXML(processInstance.getProcessDefinitionId()); // 获得 User AdminUserRespDTO startUser = adminUserApi.getUser(NumberUtils.parseLong(processInstance.getStartUserId())).getCheckedData(); DeptRespDTO dept = null; if (startUser != null) { dept = deptApi.getDept(startUser.getDeptId()).getCheckedData(); } // 拼接结果 return BpmProcessInstanceConvert.INSTANCE.convert2(processInstance, processInstanceExt, processDefinition, processDefinitionExt, bpmnXml, startUser, dept); } @Override public void cancelProcessInstance(Long userId, @Valid BpmProcessInstanceCancelReqVO cancelReqVO) { // 校验流程实例存在 ProcessInstance instance = getProcessInstance(cancelReqVO.getId()); if (instance == null) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_EXISTS); } // 只能取消自己的 if (!Objects.equals(instance.getStartUserId(), String.valueOf(userId))) { throw exception(PROCESS_INSTANCE_CANCEL_FAIL_NOT_SELF); } // 通过删除流程实例,实现流程实例的取消, // 删除流程实例,正则执行任务 ACT_RU_TASK. 任务会被删除。通过历史表查询 deleteProcessInstance(cancelReqVO.getId(), BpmProcessInstanceDeleteReasonEnum.CANCEL_TASK.format(cancelReqVO.getReason())); } /** * 获得历史的流程实例 * * @param id 流程实例的编号 * @return 历史的流程实例 */ @Override public HistoricProcessInstance getHistoricProcessInstance(String id) { return historyService.createHistoricProcessInstanceQuery().processInstanceId(id).singleResult(); } @Override public List getHistoricProcessInstances(Set ids) { return historyService.createHistoricProcessInstanceQuery().processInstanceIds(ids).list(); } @Override public void createProcessInstanceExt(ProcessInstance instance) { // 获得流程定义 ProcessDefinition definition = processDefinitionService.getProcessDefinition2(instance.getProcessDefinitionId()); // 插入 BpmProcessInstanceExtDO 对象 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getId()) .setProcessDefinitionId(definition.getId()) .setName(instance.getProcessDefinitionName()) .setStartUserId(Long.valueOf(instance.getStartUserId())) .setCategory(definition.getCategory()) .setStatus(BpmProcessInstanceStatusEnum.RUNNING.getStatus()) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); processInstanceExtMapper.insert(instanceExtDO); // 查询流程变量 List variables = processInstanceExtMapper.selectFormVariables(instance.getProcessInstanceId()); Map paramMap = variables.stream().collect(Collectors.toMap(ProcessInstanceVariablesDTO::getName, ProcessInstanceVariablesDTO::getValue)); // 补全流程实例的拓展表 processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) .setFormVariables(paramMap)); // 创建流程后,添加抄送人 processCCToUsers(instance); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtCancel(FlowableCancelledEvent event) { // 判断是否为 Reject 不通过。如果是,则不进行更新. // 因为,updateProcessInstanceExtReject 方法,已经进行更新了 if (BpmProcessInstanceDeleteReasonEnum.isRejectReason((String) event.getCause())) { return; } // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(event.getProcessInstanceId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(event.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.CANCEL.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @DataPermission(enable = false) public void updateProcessInstanceExtComplete(ProcessInstance instance) { // 需要主动查询,因为 instance 只有 id 属性 // 另外,此时如果去查询 ProcessInstance 的话,字段是不全的,所以去查询了 HistoricProcessInstance HistoricProcessInstance processInstance = getHistoricProcessInstance(instance.getId()); // 更新拓展表 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(instance.getProcessInstanceId()) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.APPROVE.getResult()); // 如果正常完全,说明审批通过 processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); Map processVariables = runtimeService.getVariables(instance.getProcessInstanceId()); String reason = (String) processVariables.get("approve_reason"); // 发送流程被通过的消息 messageService.sendMessageWhenProcessInstanceApprove(BpmProcessInstanceConvert.INSTANCE.convert2ApprovedReq(instance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } @Override @Transactional(rollbackFor = Exception.class) @DataPermission(enable = false) public void updateProcessInstanceExtReject(String id, String reason) { // 需要主动查询,因为 instance 只有 id 属性 ProcessInstance processInstance = getProcessInstance(id); // 删除流程实例,以实现驳回任务时,取消整个审批流程 deleteProcessInstance(id, StrUtil.format(BpmProcessInstanceDeleteReasonEnum.REJECT_TASK.format(reason))); // 更新 status + result // 注意,不能和上面的逻辑更换位置。因为 deleteProcessInstance 会触发流程的取消,进而调用 updateProcessInstanceExtCancel 方法, // 设置 result 为 BpmProcessInstanceStatusEnum.CANCEL,显然和 result 不一定是一致的 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessInstanceId(id) .setEndTime(LocalDateTime.now()) // 由于 ProcessInstance 里没有办法拿到 endTime,所以这里设置 .setStatus(BpmProcessInstanceStatusEnum.FINISH.getStatus()) .setResult(BpmProcessInstanceResultEnum.REJECT.getResult()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); // 发送流程被不通过的消息 messageService.sendMessageWhenProcessInstanceReject(BpmProcessInstanceConvert.INSTANCE.convert2RejectReq(processInstance, reason)); // 发送流程实例的状态事件 processInstanceResultEventPublisher.sendProcessInstanceResultEvent( BpmProcessInstanceConvert.INSTANCE.convert(this, processInstance, instanceExtDO.getResult())); } private void deleteProcessInstance(String id, String reason) { runtimeService.deleteProcessInstance(id, reason); } private String createProcessInstance0(Long userId, ProcessDefinition definition, Map variables, String businessKey) { // 校验流程定义 if (definition == null) { throw exception(PROCESS_DEFINITION_NOT_EXISTS); } if (definition.isSuspended()) { throw exception(PROCESS_DEFINITION_IS_SUSPENDED); } // 设置当前用户 FlowableUtils.setAuthenticatedUserId(userId); //获取流程发起人User AdminUserRespDTO startUser = adminUserApi.getUser(userId).getCheckedData(); //获取流程发起人部门信息 DeptRespDTO startDeptInfo = deptApi.getDept(startUser.getDeptId()).getCheckedData(); // 获取岗位信息 Set postIds = startUser.getPostIds(); ArrayList list = new ArrayList<>(postIds); //配置通用流程变量 variables.put("post_id", list.get(0).toString()); // 只获配置的首个岗位 variables.put("user_id", userId.toString()); // 配置发起人用户id variables.put("dept_id", startUser.getDeptId().toString()); // 配置发起人部门id variables.put("dept_flag", startDeptInfo.getFlag()); // 配置发起人部门flag // 创建流程实例 ProcessInstance instance = runtimeService.createProcessInstanceBuilder() .processDefinitionId(definition.getId()) .businessKey(businessKey) .name(definition.getName().trim()) .variables(variables) .start(); // 设置流程名字 runtimeService.setProcessInstanceName(instance.getId(), definition.getName()); // // 补全流程实例的拓展表 // processInstanceExtMapper.updateByProcessInstanceId(new BpmProcessInstanceExtDO().setProcessInstanceId(instance.getId()) // .setFormVariables(variables)); // // /** 创建流程后,添加抄送人 End add by yj 2024.1.4 */ // processCCToUsers(definition, instance); // /** 通过自己发起的流程 */ // approveSelfTask(instance.getId()) ; return instance.getId(); } private void approveSelfTask(String processInstanceId) { List tasks = engineTaskService.createTaskQuery().processInstanceId(processInstanceId).list(); if (tasks != null && tasks.size() > 0) { Task task = tasks.get(0); String assigneeId = task.getAssignee(); //如果当前登陆用户是审批人,那么自动审批通过 if (assigneeId.equals(SecurityFrameworkUtils.getLoginUserId().toString())) { BpmTaskApproveReqVO reqVO = new BpmTaskApproveReqVO(); reqVO.setId(task.getId()); reqVO.setReason(BpmConstants.AUTO_APPRAVAL); taskService.approveTask(getLoginUserId(), reqVO); } } } /** * 获得抄送我的流程实例的分页 * * @param userId 用户编号 * @param pageReqVO 分页请求 * @return 流程实例的分页 */ public PageResult getMyCCProcessInstancePage(Long userId, BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectCCPage(userId, pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertPage(pageResult, taskMap, null); } public List getProcessInstancesGroupByModelName(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByModelName(pageReqVO); } public List getProcessInstancesGroupByResultStatus(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); return processInstanceExtMapper.getProcessInstancesGroupByResultStatus(pageReqVO); } public PageResult getStatisticsProcessInstancePage(@Valid BpmProcessInstanceMyPageReqVO pageReqVO) { // 通过 BpmProcessInstanceExtDO 表,先查询到对应的分页 PageResult pageResult = processInstanceExtMapper.selectStatisticePage(pageReqVO); if (CollUtil.isEmpty(pageResult.getList())) { return new PageResult<>(pageResult.getTotal()); } // 获得流程 Task Map List processInstanceIds = convertList(pageResult.getList(), BpmProcessInstanceExtDO::getProcessInstanceId); Map> taskMap = taskService.getTaskMapByProcessInstanceIds(processInstanceIds); List ids = taskMap.values().stream() .flatMap(Collection::stream) .map(Task::getAssignee) .collect(Collectors.toList()); Iterator iterator = ids.iterator(); while (iterator.hasNext()) { String id = iterator.next(); if (id == null) { iterator.remove(); } } List longIds = ids.stream() .map(Long::valueOf) .collect(Collectors.toList()); //获得 审批人 User Map Map assigneeUserMap = adminUserApi.getUserMap(longIds); //获得 发起人 User Map List bpieDOs = pageResult.getList(); longIds = new ArrayList<>(); for (BpmProcessInstanceExtDO bpieDO : bpieDOs) { longIds.add(bpieDO.getStartUserId()); } Map startUserMap = adminUserApi.getUserMap(longIds); // 转换返回 return BpmProcessInstanceConvert.INSTANCE.convertStatisticsPage(pageResult, taskMap, assigneeUserMap, startUserMap); } @Resource PermissionApi permissionApi; /** * 根据数据权限,查询关联操作的用户IDS * * @param pageReqVO * @param * @return */ private T getUserids(T pageReqVO) { try { Class clazz = (Class) pageReqVO.getClass(); Field idField = clazz.getDeclaredField("userIds"); idField.setAccessible(true); // 设置可访问性 Long[] userIds = null; Long userId = WebFrameworkUtils.getLoginUserId(); DeptDataPermissionRespDTO deptDataPermission = permissionApi.getDeptDataPermission(userId).getCheckedData(); //查询全部 if (deptDataPermission.getAll()) { //idField.set(pageReqVO, null); // 设置属性值 return pageReqVO; } // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) && Boolean.FALSE.equals(deptDataPermission.getSelf())) { //设置成0,一个不存在的用户Id,就查询不到数据了。 userIds = new Long[]{0L}; idField.set(pageReqVO, userIds); return pageReqVO; } //情况三 至查询自己 if (deptDataPermission.getSelf()) { userIds = new Long[]{userId}; idField.set(pageReqVO, userIds); return pageReqVO; } Set deptIds = deptDataPermission.getDeptIds(); //查询部门关联的用户Id List users = adminUserApi.getUserListByDeptIds(deptIds).getCheckedData(); List tempList = new ArrayList<>(); for (AdminUserRespDTO user : users) { Long id = user.getId(); tempList.add(id); } tempList.add(userId); userIds = tempList.stream().toArray(Long[]::new); //将临时的List集合转换成数组集合 idField.set(pageReqVO, userIds); return pageReqVO; } catch (Exception exception) { exception.printStackTrace(); throw exception(BPM_SYSTEM_BUG); } } /** * /创建流程后,添加抄送人 Begin add by yj 2024.1.4 * 在设计流程的时候,需要添加一个任务块 名字必须叫Activity_cc 分配权限的时候,需要选择用户组。 * * @param definition * @param instance */ private void processCCToUsers(ProcessDefinition definition, ProcessInstance instance) { //获取bpm_task_assign_reule (Bpm 任务规则表)的流程中有没有配置抄送节点 固定抄送名称为:Activity_cc String processDefinitionId = definition.getId(); List rules = taskRuleMapper.selectListByProcessDefinitionId(processDefinitionId, null); String BpmConstantsName = BpmConstants.CC_NAME; // 获取发起人信息 AdminUserRespDTO userRespDTO = adminUserApi.getUser(Long.valueOf(instance.getStartUserId())).getCheckedData(); DeptRespDTO deptRespDTO = deptApi.getDept(userRespDTO.getDeptId()).getCheckedData(); //发起人是深圳分公司 if (deptRespDTO.getFlag().contains("136")) { BpmConstantsName = BpmConstants.CCSZ_NAME; } for (BpmTaskAssignRuleDO rule : rules) { String key = rule.getTaskDefinitionKey(); //任务名称 Integer type = rule.getType(); if (!key.isEmpty() && key.equals(BpmConstantsName) && type == 40) { StringBuffer str = new StringBuffer(); Set options = rule.getOptions(); List list = new ArrayList(options); for (Long groupId : list) { //需要根据这个groupId,查询这个组中的用户id BpmUserGroupDO userGroup = userGroupService.getUserGroup(groupId); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } //流程是采购计划时 if (definition.getKey().equals(BpmOAProcureServiceImpl.PROCESS_KEY)) { //发起人部门为 生产部及以下时 if (deptRespDTO.getFlag().contains("130")) { //添加 供应部抄送 BpmUserGroupDO userGroup = userGroupService.getUserGroup(121L); Set userIds = userGroup.getMemberUserIds(); List userIdList = new ArrayList(userIds); for (Long user_id : userIdList) { str.append("[").append(user_id).append("]"); } } } String ccids = str.toString(); //根据processDefinitionId 将ccids保存到bpm_process_instance_ext中的ccids字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO().setProcessDefinitionId(processDefinitionId) .setCcids(ccids).setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); break; } } } /** * 创建流程后,添加抄送人 * @param instance 流程实例 */ private void processCCToUsers(ProcessInstance instance) { // 根据流程名称、流程发起人 查询流程配置的抄送人信息 List processCcList = processCcService.getCCListByName(instance.getName(), Long.valueOf(instance.getStartUserId())); // 提取抄送信息用中对应的用户组编号 Set userGroupIds = processCcList.stream() .flatMap(data -> data.getUserGroupId().stream()) .collect(Collectors.toSet()); if (CollectionUtil.isNotEmpty(userGroupIds)) { // 获取用户组信息 List userGroups = userGroupService.getUserGroupList(userGroupIds); // 提取用户组中对应的用户ID Set userIds = userGroups.stream() .flatMap(data -> data.getMemberUserIds().stream()) .collect(Collectors.toSet()); // 将用户ID列表转换为字符串 String ccIds = userIds.stream() .map(id -> "[" + id + "]") // 每个值用方括号包裹 .collect(Collectors.joining()); //根据processDefinitionId 将ccIds保存到bpm_process_instance_ext中的ccIds字段 BpmProcessInstanceExtDO instanceExtDO = new BpmProcessInstanceExtDO() .setProcessDefinitionId(instance.getProcessDefinitionId()) .setCcids(ccIds) .setProcessInstanceId(instance.getProcessInstanceId()); processInstanceExtMapper.updateByProcessInstanceId(instanceExtDO); } } @Override public List getUserProcessTpo10(BpmProcessInstanceStatisticsReqVO pageReqVO) { //按审核人分组查询,统计已完成流程数量及平均耗时间 List respVOS = processInstanceExtMapper.getUserProcessTpo10(pageReqVO); if (respVOS == null || respVOS.size() == 0) { return null; } List idList = respVOS.stream() .map(BpmProcessFinishStatisticsRespVO::getUserId) .collect(Collectors.toList()); //根据userId,查询UserMap Map userMap = adminUserApi.getUserMap(idList); Long[] idsArray = new Long[userMap.size()]; // 使用 map 的 keySet() 方法获取键集合 Set keys = userMap.keySet(); // 遍历键集合,将每个键添加到数组中 int index = 0; for (Long key : keys) { idsArray[index++] = key; } pageReqVO.setUserIds(idsArray); //按审核人分组查询,未审批完成的流程数量 List bpmTaskExtDOs = processInstanceExtMapper.selectUnfinishProcessCount(pageReqVO); //按审核人分组查询,未完成的记录数 Map unFinfishCountCountMap = new HashMap<>(); for (BpmProcessFinishStatisticsRespVO item : bpmTaskExtDOs) { unFinfishCountCountMap.put(item.getUserId(), item.getUnFinfishCount()); } respVOS.forEach(respVO -> respVO.setName(userMap.get(respVO.getUserId()).getNickname())); respVOS.forEach(respVO -> respVO.setUnFinfishCount(unFinfishCountCountMap.get(respVO.getUserId()))); //获取排行榜第一记录的耗时,作为基础数据 double num = Double.parseDouble(respVOS.get(0).getUserTime()); // 先将字符串转换为双精度浮点数 int baseNumber = (int) num; // 再通过类型转换操作符将其转换为整数 DecimalFormat df = new DecimalFormat("#.00"); respVOS.forEach(respVO -> { //格式化流程完成率 float finfishCount = (float) respVO.getFinfishCount(); float unFinfishCount = respVO.getUnFinfishCount() == null ? 0 : respVO.getUnFinfishCount(); float all = finfishCount + unFinfishCount; float result = finfishCount / all; float rate = result * 100; respVO.setCompletionRate(df.format(rate) + "%"); double dValue = Double.parseDouble(respVO.getUserTime()); // 将字符串转换为double类型 int roundedValue = (int) Math.round(dValue); // 使用Math.round()进行四舍五入,并转换为int类型 respVO.setUserTime(roundedValue + ""); //格式化进度百度比, 参照最高的数据进行百分比显示 double percentage = ((int) Double.parseDouble(respVO.getUserTime()) / (double) baseNumber) * 100; respVO.setPercentage((int) Math.round(percentage)); //设置未完成 respVO.setUnFinfishCount(Integer.valueOf((int) unFinfishCount)); }); return respVOS; } @Override @DataPermission(enable = false) public BpmProcessInstanceExtDO getProcessInstanceDO(String id) { return processInstanceExtMapper.selectByProcessInstanceId(id); } @Resource private FileApi fileApi; @Resource @Lazy // 解决循环依赖 private BpmOAReimbursementService reimbursementService; @Resource @Lazy // 解决循环依赖 private BpmOACashService cashService; @Resource @Lazy // 解决循环依赖 private BpmOAImprestService imprestService; @Override public BpmProcessInstancePrintDataRespVO getOAReportPrintData(BpmProcessInstancePrintDataReqVO reqVO) { BpmProcessInstancePrintDataRespVO bpmProcessInstancePrintDataRespVO = new BpmProcessInstancePrintDataRespVO(); String key = reqVO.getKey(); //流程标识 String processInstanceId = reqVO.getId(); //流程实例ID bpmProcessInstancePrintDataRespVO.setId(processInstanceId); bpmProcessInstancePrintDataRespVO.setKey(key); BpmProcessInstanceRespVO bpmProcessInstance = getProcessInstanceVO(processInstanceId); Long businessKey = Long.valueOf(bpmProcessInstance.getBusinessKey()); //流程业务表-主键ID // 判断是否可见外勤人员信息 List userIds = new ArrayList<>(); String type = configApi.getConfigKey("sys.user.type").getCheckedData(); if ("1".equals(type)) { //不可见时 // 获取所有外勤人员 用户编号 userIds = adminUserApi.getUserIdsByUserNature(4).getCheckedData(); } // 获得流程审批信息 List taskRespVOList = taskService.getTaskListByProcessInstanceId(processInstanceId); // 移除外勤人员信息 List finalUserIds = userIds; taskRespVOList.removeIf(data -> finalUserIds.contains(data.getAssigneeUser().getId())); //给User添加签名地址 taskRespVOList.forEach(taskRespVO -> taskRespVO.getAssigneeUser().setSignURL( fileApi.getUserSignImgPath( taskRespVO.getAssigneeUser().getId() ).getData() ) ); //获取流程抄送用户编号 BpmProcessInstanceExtDO processInstanceExtDO = getProcessInstanceDO(processInstanceId); //获取流程抄送用户信息 List ccUserIds = new ArrayList<>(); if (processInstanceExtDO.getCcids() != null && !processInstanceExtDO.getCcids().isEmpty()) { Pattern pattern = Pattern.compile("\\[(\\d+)]"); Matcher matcher = pattern.matcher(processInstanceExtDO.getCcids()); while (matcher.find()) { ccUserIds.add(Long.parseLong(matcher.group(1))); } // 移除 外勤人员信息 ccUserIds.removeAll(userIds); } List userRespDTOS = adminUserApi.getUserList(ccUserIds).getCheckedData(); //获取抄送用户部门信息 Map deptMapDTO = deptApi.getDeptMap(convertSet(userRespDTOS, AdminUserRespDTO::getDeptId)); if ("oa_reimbursement".equals(key)) { //报销流程 BpmOAReimbursementDO reimbursement = reimbursementService.getReimbursement(businessKey); BpmOAReimbursementRespVO bpmOAReimbursementRespVO = reimbursementService.convert(reimbursement); //报销业务数据 // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(reimbursement.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(reimbursement.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 bpmOAReimbursementRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 bpmOAReimbursementRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOAReimbursementPrintDataRespVO.CCUser cc = new BpmOAReimbursementPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOAReimbursementPrintDataRespVO reimbursementPrintData = new BpmOAReimbursementPrintDataRespVO(); reimbursementPrintData.setBpmOAReimbursementRespVO(bpmOAReimbursementRespVO); reimbursementPrintData.setProcessTasks(taskRespVOList); reimbursementPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOAReimbursementPrintDataRespVO(reimbursementPrintData); } if ("oa_cash".equals(key)) { BpmOACashDO cashDO = cashService.getCash(businessKey); BpmOACashRespVO cashRespVO = cashService.convertCash(cashDO); // 移除自己得审批节点 taskRespVOList.removeIf(data -> data.getAssigneeUser().getId().equals(cashDO.getUserId())); //备用金信息查询 BpmOAImprestDO bpmOAImprestDO = imprestService.getImprest(cashDO.getImprestId()); if (bpmOAImprestDO != null) { //设置备用金 金额 cashRespVO.setAmount(bpmOAImprestDO.getAmount()); // 设置备用金 剩余金额 cashRespVO.setRemainingAmount(bpmOAImprestDO.getAmount().subtract(bpmOAImprestDO.getReimbursedAmount())); } // 设置抄送人信息 List ccUsers = userRespDTOS.stream().map(user -> { BpmOACashPrintDataRespVO.CCUser cc = new BpmOACashPrintDataRespVO.CCUser(); cc.setCcUserId(user.getId()); cc.setCcUserName(user.getNickname()); cc.setCcDeptName(deptMapDTO.get(user.getDeptId()).getName()); return cc; }).collect(Collectors.toList()); BpmOACashPrintDataRespVO cashPrintData = new BpmOACashPrintDataRespVO(); cashPrintData.setBpmOACashRespVO(cashRespVO); cashPrintData.setProcessTasks(taskRespVOList); cashPrintData.setCcUsers(ccUsers); bpmProcessInstancePrintDataRespVO.setBpmOACashPrintDataRespVO(cashPrintData); } return bpmProcessInstancePrintDataRespVO; } @Override public Map> getProcessInstanceResultStatusStatisticsGroupTime(BpmProcessInstanceStatisticsReqVO pageReqVO) { pageReqVO = getUserids(pageReqVO); pageReqVO.setRecentDays(pageReqVO.getRecentDays() == null ? 7 : pageReqVO.getRecentDays()); List list = processInstanceExtMapper.getProcessInstanceResultStatusStatisticsGroupTime(pageReqVO); // -- 获取到日期列表 LocalDateTime now = LocalDateTimeUtil.now(); LocalDateTime offset = LocalDateTimeUtil.offset(LocalDateTimeUtil.now(), -1L * pageReqVO.getRecentDays(), ChronoUnit.DAYS); List dateList = DateUtils.betweenDayList(offset, now); //根据时间分组 Map> map = list.stream().collect(Collectors.groupingBy(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getTime)); List keys = new ArrayList<>(CollectionUtil.subtract(dateList, new ArrayList<>(map.keySet()))); if (CollectionUtil.isNotEmpty(keys)) { for (String key : keys) { map.put(key, new ArrayList<>()); } } List statusList = Arrays.asList(1, 2, 3, 4); for (Map.Entry> entry : map.entrySet()) { List items = entry.getValue(); List results = items.stream().map(BpmProcessInstanceResultStatusStatisticsGroupTimeVO::getResult).collect(Collectors.toList()); List saveList = new ArrayList<>(CollectionUtil.subtract(statusList, results)); // -- 如果没有的话组装上缺少的 if (CollectionUtil.isNotEmpty(saveList)) { for (Integer status : saveList) { items.add(new BpmProcessInstanceResultStatusStatisticsGroupTimeVO() .setTime(entry.getKey()) .setTotalCount(0) .setResult(status) .setName("")); } } } return map; } } \ No newline at end of file From 066ccf702178468b34bcbfad20ea91e411b82ba5 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sat, 23 Nov 2024 10:52:13 +0800 Subject: [PATCH 08/18] =?UTF-8?q?feat(system):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加项目管理相关的数据对象、控制器、服务接口和实现类 - 实现项目管理的 CRUD 功能,包括创建、更新、删除和查询项目信息 - 添加租赁客户管理功能 - 优化文件更新接口,支持批量更新- 新增用户信息查询接口- 添加系统错误码常量 --- .../bpm/dal/dataobject/oa/BpmOARefundDO.java | 38 ++++ .../yudao/module/infra/api/file/FileApi.java | 7 +- .../module/infra/api/file/FileApiImpl.java | 4 +- .../infra/service/file/FileService.java | 2 +- .../infra/service/file/FileServiceImpl.java | 7 +- .../system/enums/ErrorCodeConstants.java | 12 ++ .../admin/project/ProjectController.java | 177 ++++++++++++++++++ .../admin/project/vo/ProjectPageReqVO.java | 53 ++++++ .../admin/project/vo/ProjectRespVO.java | 72 +++++++ .../admin/project/vo/ProjectSaveReqVO.java | 69 +++++++ .../rental/RentalCustomerController.java | 97 ++++++++++ .../rental/RentalDepositRecordController.java | 64 +++++++ .../rental/RentalItemsRecordController.java | 76 ++++++++ .../admin/rental/RentalOrderController.java | 108 +++++++++++ .../vo/customer/RentalCustomerPageReqVO.java | 40 ++++ .../vo/customer/RentalCustomerRespVO.java | 37 ++++ .../vo/customer/RentalCustomerSaveReqVO.java | 36 ++++ .../customer/RentalCustomerStatusReqVO.java | 18 ++ .../vo/itemsrecord/RentalItemsCountReqVO.java | 15 ++ .../RentalItemsRecordPageReqVO.java | 32 ++++ .../itemsrecord/RentalItemsRecordRespVO.java | 30 +++ .../RentalItemsRecordSaveReqVO.java | 32 ++++ .../rental/vo/order/RentalOrderPageReqVO.java | 39 ++++ .../rental/vo/order/RentalOrderRespVO.java | 57 ++++++ .../rental/vo/order/RentalOrderSaveReqVO.java | 48 +++++ .../RentalDepositAmountReqVO.java | 17 ++ .../RentalDepositRecordPageReqVO.java | 42 +++++ .../RentalDepositRecordRespVO.java | 63 +++++++ .../RentalDepositRecordSaveReqVO.java | 53 ++++++ .../controller/admin/user/UserController.java | 10 + .../dal/dataobject/project/ProjectDO.java | 94 ++++++++++ .../dataobject/rental/RentalCustomerDO.java | 54 ++++++ .../rental/RentalDepositRecordDO.java | 74 ++++++++ .../rental/RentalItemsRecordDO.java | 44 +++++ .../dal/dataobject/rental/RentalOrderDO.java | 60 ++++++ .../dal/mysql/project/ProjectMapper.java | 32 ++++ .../mysql/rental/RentalCustomerMapper.java | 29 +++ .../rental/RentalDepositRecordMapper.java | 35 ++++ .../mysql/rental/RentalItemsRecordMapper.java | 29 +++ .../dal/mysql/rental/RentalOrderMapper.java | 49 +++++ .../system/dal/redis/RedisKeyConstants.java | 7 + .../service/project/ProjectService.java | 55 ++++++ .../service/project/ProjectServiceImpl.java | 73 ++++++++ .../service/rental/RentalCustomerService.java | 69 +++++++ .../rental/RentalCustomerServiceImpl.java | 91 +++++++++ .../rental/RentalDepositRecordService.java | 64 +++++++ .../RentalDepositRecordServiceImpl.java | 129 +++++++++++++ .../rental/RentalItemsRecordService.java | 60 ++++++ .../rental/RentalItemsRecordServiceImpl.java | 111 +++++++++++ .../service/rental/RentalOrderService.java | 63 +++++++ .../rental/RentalOrderServiceImpl.java | 148 +++++++++++++++ .../system/service/user/AdminUserService.java | 9 + .../service/user/AdminUserServiceImpl.java | 8 + .../rental/RentalDepositRecordMapper.xml | 25 +++ .../mapper/rental/RentalItemsRecordMapper.xml | 24 +++ .../mapper/rental/RentalOrderMapper.xml | 21 +++ 56 files changed, 2800 insertions(+), 12 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalCustomerController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalDepositRecordController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerStatusReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsCountReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositAmountReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordPageReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordRespVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/project/ProjectDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalCustomerDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalDepositRecordDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalItemsRecordDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalCustomerMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalDepositRecordMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalOrderMapper.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalDepositRecordMapper.xml create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalOrderMapper.xml diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java new file mode 100644 index 00000000..f359ff51 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java @@ -0,0 +1,38 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * OA 转正申请 DO + * + * + * @author 符溶馨 + + */ +@TableName(value ="bpm_oa_refund", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOARefundDO extends BaseDO { + + /** + * 出差表单主键 + */ + @TableId + private Long id; + + /** + * 申请人的用户编号 + * 关联 AdminUserDO 的 id 属性 + */ + private Long userId; + + private String orderNo; + +} diff --git a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java index cb069631..efff9173 100644 --- a/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java +++ b/yudao-module-infra/yudao-module-infra-api/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApi.java @@ -83,10 +83,9 @@ public interface FileApi { @RequestBody byte[] content); @PostMapping(PREFIX + "/updateBusinessFile") - @Operation(summary = "修改BusinessFile文件中的 businessInstanceId | 入职申请用") - CommonResult updateBusinessFileFormEntry(@RequestParam("url") String url, - @RequestParam("businessInstanceId") String businessInstanceId); - + @Operation(summary = "修改BusinessFile文件中的 businessInstanceId") + CommonResult updateBusinessFile(@RequestParam("url") List url, + @RequestParam("businessInstanceId") String businessInstanceId); @DeleteMapping(PREFIX + "/deleteBpmFile") @Operation(summary = "删除工作流附件") diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java index 2c84494c..d4bc6a19 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/api/file/FileApiImpl.java @@ -67,9 +67,9 @@ public class FileApiImpl implements FileApi { @Override @SneakyThrows - public CommonResult updateBusinessFileFormEntry(String url, String businessInstanceId) { + public CommonResult updateBusinessFile(List url, String businessInstanceId) { - fileService.uploadBusinessFileFormEntry(url, businessInstanceId); + fileService.uploadBusinessFile(url, businessInstanceId); return success(true); } diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java index a4d2b716..615a5f82 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileService.java @@ -109,7 +109,7 @@ public interface FileService { * 更新文件的流程实例ID | 入职申请用 * @param url 文件地址 */ - void uploadBusinessFileFormEntry(String url, String businessInstanceId); + void uploadBusinessFile(List url, String businessInstanceId); /** * 获取用户的签名图片地址 diff --git a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java index f8fcb47f..0cb0e897 100644 --- a/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java +++ b/yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/service/file/FileServiceImpl.java @@ -337,14 +337,11 @@ public class FileServiceImpl implements FileService { @Override @SneakyThrows - public void uploadBusinessFileFormEntry(String url, String businessInstanceId) { + public void uploadBusinessFile(List url, String businessInstanceId) { LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper<>(); - lambdaUpdateWrapper.eq(BusinessFileDO::getUrl, url); + lambdaUpdateWrapper.in(BusinessFileDO::getUrl, url); lambdaUpdateWrapper.set(BusinessFileDO::getBusinessInstanceId, businessInstanceId); // 假设 bid 是要更新的 bid 值 - lambdaUpdateWrapper.set(BusinessFileDO::getUploadUserId, businessInstanceId); - lambdaUpdateWrapper.set(BusinessFileDO::getCreator, businessInstanceId); - lambdaUpdateWrapper.set(BusinessFileDO::getUpdater, businessInstanceId); // 调用 MyBatis Plus 的 update 方法执行批量更新 businessFileMapper.update(null, lambdaUpdateWrapper); diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java index e9d3b11a..8befb466 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/ErrorCodeConstants.java @@ -270,4 +270,16 @@ public interface ErrorCodeConstants { ErrorCode PAYSLIP_EXISTS = new ErrorCode(1_012_002_007, "所选公司在当前月份已上传工资条!如需修改,请勾选覆盖导入。"); ErrorCode PAYSLIP_ID_CARD_ERROR = new ErrorCode(1_012_002_008, "【{}】身份证输入有误,请核对后导入!"); ErrorCode PAYSLIP_ISSUED = new ErrorCode(1_012_002_009, "所选公司在当前月份的工资条已下发,不能修改!"); + + // ========== 租赁相关 1-013-001-001 ========== + ErrorCode RENTAL_CUSTOMER_NOT_EXISTS = new ErrorCode(1_013_001_001, "租赁客户不存在"); + ErrorCode RENTAL_ORDER_NOT_EXISTS = new ErrorCode(1_013_001_002, "租赁订单不存在"); + ErrorCode RENTAL_ITEMS_RECORD_NOT_EXISTS = new ErrorCode(1_013_001_003, "租赁物品记录不存在"); + ErrorCode RENTAL_DEPOSIT_RECORD_NOT_EXISTS = new ErrorCode(1_013_001_004, "租赁订单押金记录不存在"); + ErrorCode RENTAL_ITEMS_NUMBER_EXCESS = new ErrorCode(1_013_001_005, "归还数量不能大于剩余租借数量!"); + ErrorCode RENTAL_RECEIVED_AMOUNT_EXCESS = new ErrorCode(1_013_001_006, "收款金额不能大于押金金额!"); + ErrorCode RENTAL_REFUND_AMOUNT_EXCESS = new ErrorCode(1_013_001_007, "退款金额不能大于收款金额!"); + + // ========== 项目管理相关 1-014-001-001 ========== + ErrorCode PROJECT_NOT_EXISTS = new ErrorCode(1_014_001_001, "项目不存在!"); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java new file mode 100644 index 00000000..c77d1c73 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java @@ -0,0 +1,177 @@ +package cn.iocoder.yudao.module.system.controller.admin.project; + +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectRespVO; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; +import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.project.ProjectService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.*; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +@Tag(name = "管理后台 - 项目管理") +@RestController +@RequestMapping("/system/project") +@Validated +public class ProjectController { + + @Resource + private ProjectService projectService; + + @Resource + private AdminUserService userService; + + @Resource + private DeptService deptService; + + @PostMapping("/create") + @Operation(summary = "创建项目管理") + @PreAuthorize("@ss.hasPermission('system:project:create')") + public CommonResult createProject(@Valid @RequestBody ProjectSaveReqVO createReqVO) { + return success(projectService.createProject(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新项目管理") + @PreAuthorize("@ss.hasPermission('system:project:update')") + public CommonResult updateProject(@Valid @RequestBody ProjectSaveReqVO updateReqVO) { + projectService.updateProject(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除项目管理") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:project:delete')") + public CommonResult deleteProject(@RequestParam("id") Long id) { + projectService.deleteProject(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得项目管理") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:project:query')") + public CommonResult getProject(@RequestParam("id") Long id) { + ProjectDO project = projectService.getProject(id); + ProjectRespVO respVO = BeanUtils.toBean(project, ProjectRespVO.class); + if (respVO != null) { + // 获取项目中所有人员的用户编号列表 + Set userIds = respVO.getStaff() == null ? new HashSet<>() : respVO.getStaff(); + userIds.add(respVO.getDirectorUserId()); + + // 获取项目中所有部门编号列表 + Set deptIds = respVO.getParticipationDept() == null ? new HashSet<>() : respVO.getParticipationDept(); + deptIds.add(respVO.getResponsibleDept()); + + // 获取所有用户信息 + List userDOS = userService.getUserList(userIds); + Map userMap = convertMap(userDOS, AdminUserDO::getId); + // 获取所有部门信息 + List deptDOS = deptService.getDeptList(deptIds); + Map deptMap = convertMap(deptDOS, DeptDO::getId); + + // 筛选出不是责任人的用户信息 + List userVOs = userDOS.stream() + .filter(user -> !user.getId().equals(respVO.getDirectorUserId())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任人名称 + respVO.setDirectorUserName(userMap.get(respVO.getDirectorUserId()).getNickname()); + // 拼接项目人员名称 + respVO.setStaffName(userVOs.stream().map(AdminUserDO::getNickname).collect(Collectors.joining("、"))); + + // 筛选出不是责任人部门的部门信息 + List deptVOs = deptDOS.stream() + .filter(dept -> !dept.getId().equals(respVO.getResponsibleDept())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任部门名称 + respVO.setResponsibleDeptName(deptMap.get(respVO.getResponsibleDept()).getName()); + // 拼接参与部门名称 + respVO.setParticipationDeptName(deptVOs.stream().map(DeptDO::getName).collect(Collectors.joining("、"))); + } + + return success(respVO); + } + + @GetMapping("/page") + @Operation(summary = "获得项目管理分页") + @PreAuthorize("@ss.hasPermission('system:project:query')") + @DataPermission(enable = false) + public CommonResult> getProjectPage(@Valid ProjectPageReqVO pageReqVO) { + PageResult pageResult = projectService.getProjectPage(pageReqVO); + PageResult respVOs = BeanUtils.toBean(pageResult, ProjectRespVO.class); + + if (CollectionUtil.isNotEmpty(respVOs.getList())) { + // 获取项目中所有人员的用户编号列表 + List userIds = respVOs.getList().stream() + .filter(item -> Objects.nonNull(item.getStaff())) + .flatMap(item -> item.getStaff().stream()) + .collect(Collectors.toList()); + userIds.addAll(convertList(respVOs.getList(), ProjectRespVO::getDirectorUserId)); + + // 获取项目中所有部门编号列表 + List deptIds = respVOs.getList().stream() + .filter(item -> Objects.nonNull(item.getParticipationDept())) + .flatMap(item -> item.getParticipationDept().stream()) + .collect(Collectors.toList()); + deptIds.addAll(convertList(respVOs.getList(), ProjectRespVO::getResponsibleDept)); + + // 获取所有用户信息 + List userDOS = userService.getUserList(userIds); + Map userMap = convertMap(userDOS, AdminUserDO::getId); + // 获取所有部门信息 + List deptDOS = deptService.getDeptList(deptIds); + Map deptMap = convertMap(deptDOS, DeptDO::getId); + respVOs.getList().forEach(item -> { + // 筛选出不是责任人的用户信息 + List userVOs = userDOS.stream() + .filter(user -> !user.getId().equals(item.getDirectorUserId())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任人名称 + item.setDirectorUserName(userMap.get(item.getDirectorUserId()).getNickname()); + // 拼接项目人员名称 + item.setStaffName(userVOs.stream().map(AdminUserDO::getNickname).collect(Collectors.joining("、"))); + + // 筛选出不是责任人部门的部门信息 + List deptVOs = deptDOS.stream() + .filter(dept -> !dept.getId().equals(item.getResponsibleDept())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任部门名称 + item.setResponsibleDeptName(deptMap.get(item.getResponsibleDept()).getName()); + // 拼接参与部门名称 + item.setParticipationDeptName(deptVOs.stream().map(DeptDO::getName).collect(Collectors.joining("、"))); + }); + } + + return success(respVOs); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectPageReqVO.java new file mode 100644 index 00000000..5a597577 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectPageReqVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.system.controller.admin.project.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 项目管理分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class ProjectPageReqVO extends PageParam { + + @Schema(description = "项目编号") + private String projectNo; + + @Schema(description = "项目类型 | 字典值参考system_project_type", example = "1") + private Integer type; + + @Schema(description = "项目名称") + private String name; + + @Schema(description = "责任部门") + private Long responsibleDept; + + @Schema(description = "参与部门集合") + private String participationDept; + + @Schema(description = "责任人用户编号") + private Long directorUserId; + + @Schema(description = "项目开始时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDate[] startDate; + + @Schema(description = "项目结束时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDate[] endDate; + + @Schema(description = "是否长期 | 0否 1是") + private Integer isLongTerm; + + @Schema(description = "项目状态 | 1 进行中 2已完成", example = "1") + private Integer status; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectRespVO.java new file mode 100644 index 00000000..2feec509 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectRespVO.java @@ -0,0 +1,72 @@ +package cn.iocoder.yudao.module.system.controller.admin.project.vo; + +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Set; + +@Schema(description = "管理后台 - 项目管理 Response VO") +@Data +public class ProjectRespVO { + + @Schema(description = "项目管理表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "项目编号", requiredMode = Schema.RequiredMode.REQUIRED) + private String projectNo; + + @Schema(description = "项目类型 | 字典值参考system_project_type", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer type; + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("项目名称") + private String name; + + @Schema(description = "责任部门", requiredMode = Schema.RequiredMode.REQUIRED) + private Long responsibleDept; + + @Schema(description = "责任部门名称") + private String responsibleDeptName; + + @Schema(description = "参与部门集合", requiredMode = Schema.RequiredMode.REQUIRED) + private Set participationDept; + + @Schema(description = "参与部门名称") + private String participationDeptName; + + @Schema(description = "责任人用户编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long directorUserId; + + @Schema(description = "责任人用户名称") + private String directorUserName; + + @Schema(description = "项目开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDate startDate; + + @Schema(description = "项目结束时间") + private LocalDate endDate; + + @Schema(description = "是否长期 | 0否 1是") + private Integer isLongTerm; + + @Schema(description = "项目预算") + private Integer projectBudget; + + @Schema(description = "项目内容", requiredMode = Schema.RequiredMode.REQUIRED) + private String content; + + @Schema(description = "项目人员用户编号集合") + private Set staff; + + @Schema(description = "项目人员用户名称") + private String staffName; + + @Schema(description = "项目状态 | 1 进行中 2已完成", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java new file mode 100644 index 00000000..950dfe6f --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/vo/ProjectSaveReqVO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.system.controller.admin.project.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; +import java.util.Map; +import java.util.Set; + +@Schema(description = "管理后台 - 项目管理新增/修改 Request VO") +@Data +public class ProjectSaveReqVO { + + @Schema(description = "项目管理表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "项目编号") + private String projectNo; + + @Schema(description = "项目类型 | 字典值参考system_project_type", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "项目类型 | 字典值参考system_project_type不能为空") + private Integer type; + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "项目名称不能为空") + private String name; + + @Schema(description = "责任部门", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任部门不能为空") + private Long responsibleDept; + + @Schema(description = "参与部门集合", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "参与部门集合不能为空") + private Set participationDept; + + @Schema(description = "责任人用户编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任人用户编号不能为空") + private Long directorUserId; + + @Schema(description = "项目开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目开始时间不能为空") + private LocalDate startDate; + + @Schema(description = "项目结束时间") + private LocalDate endDate; + + @Schema(description = "是否长期 | 0否 1是") + private Integer isLongTerm; + + @Schema(description = "项目预算") + private Integer projectBudget; + + @Schema(description = "项目内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "项目内容不能为空") + private String content; + + @Schema(description = "项目人员用户编号集合") + private Set staff; + + @Schema(description = "项目额外属性") + private Map dynamicAttribute; + + @Schema(description = "项目状态 | 1 进行中 2已完成", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "项目状态 | 1 进行中 2已完成不能为空") + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalCustomerController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalCustomerController.java new file mode 100644 index 00000000..f0e48d98 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalCustomerController.java @@ -0,0 +1,97 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerStatusReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.service.rental.RentalCustomerService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + + +@Tag(name = "管理后台 - 租赁客户") +@RestController +@RequestMapping("/system/rental-customer") +@Validated +public class RentalCustomerController { + + @Resource + private RentalCustomerService rentalCustomerService; + + @PostMapping("/create") + @Operation(summary = "创建租赁客户") + @PreAuthorize("@ss.hasPermission('system:rental-customer:create')") + public CommonResult createRentalCustomer(@Valid @RequestBody RentalCustomerSaveReqVO createReqVO) { + return success(rentalCustomerService.createRentalCustomer(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租赁客户") + @PreAuthorize("@ss.hasPermission('system:rental-customer:update')") + public CommonResult updateRentalCustomer(@Valid @RequestBody RentalCustomerSaveReqVO updateReqVO) { + rentalCustomerService.updateRentalCustomer(updateReqVO); + return success(true); + } + + @PutMapping("/update-status") + @Operation(summary = "更新租赁客户状态") + @PreAuthorize("@ss.hasPermission('system:rental-customer:update')") + public CommonResult updateRentalCustomer(@RequestBody RentalCustomerStatusReqVO updateReqVO) { + rentalCustomerService.updateRentalCustomerStatus(updateReqVO); + return success(true); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租赁客户") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:rental-customer:delete')") + public CommonResult deleteRentalCustomer(@RequestParam("id") Long id) { + rentalCustomerService.deleteRentalCustomer(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租赁客户") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:rental-customer:query')") + public CommonResult getRentalCustomer(@RequestParam("id") Long id) { + RentalCustomerDO rentalCustomer = rentalCustomerService.getRentalCustomer(id); + return success(BeanUtils.toBean(rentalCustomer, RentalCustomerRespVO.class)); + } + + @GetMapping("/get-list") + @Operation(summary = "获得开启状态的租赁客户列表") + @PreAuthorize("@ss.hasPermission('system:rental-customer:query')") + public CommonResult> getRentalCustomerList() { + List rentalCustomer = rentalCustomerService.getRentalCustomerList(); + return success(BeanUtils.toBean(rentalCustomer, RentalCustomerRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租赁客户分页") + @PreAuthorize("@ss.hasPermission('system:rental-customer:query')") + public CommonResult> getRentalCustomerPage(@Valid RentalCustomerPageReqVO pageReqVO) { + PageResult pageResult = rentalCustomerService.getRentalCustomerPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, RentalCustomerRespVO.class)); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalDepositRecordController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalDepositRecordController.java new file mode 100644 index 00000000..867eadbb --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalDepositRecordController.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import cn.iocoder.yudao.module.system.service.rental.RentalDepositRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + + +@Tag(name = "管理后台 - 租赁订单押金记录") +@RestController +@RequestMapping("/system/rental-deposit-record") +@Validated +public class RentalDepositRecordController { + + @Resource + private RentalDepositRecordService rentalDepositRecordService; + + @PostMapping("/create") + @Operation(summary = "创建租赁订单押金记录") + @PreAuthorize("@ss.hasPermission('system:rental-deposit-record:create')") + public CommonResult createRentalDepositRecord(@Valid @RequestBody RentalDepositRecordSaveReqVO createReqVO) { + return success(rentalDepositRecordService.createRentalDepositRecord(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租赁订单押金记录") + @PreAuthorize("@ss.hasPermission('system:rental-deposit-record:update')") + public CommonResult updateRentalDepositRecord(@Valid @RequestBody RentalDepositRecordSaveReqVO updateReqVO) { + rentalDepositRecordService.updateRentalDepositRecord(updateReqVO); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租赁订单押金记录") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:rental-deposit-record:query')") + public CommonResult getRentalDepositRecord(@RequestParam("id") Long id) { + RentalDepositRecordDO rentalDepositRecord = rentalDepositRecordService.getRentalDepositRecord(id); + return success(BeanUtils.toBean(rentalDepositRecord, RentalDepositRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租赁订单押金记录分页") + @PreAuthorize("@ss.hasPermission('system:rental-deposit-record:query')") + public CommonResult> getRentalDepositRecordPage(@Valid RentalDepositRecordPageReqVO pageReqVO) { + PageResult pageResult = rentalDepositRecordService.getRentalDepositRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, RentalDepositRecordRespVO.class)); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java new file mode 100644 index 00000000..3183f197 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java @@ -0,0 +1,76 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalItemsRecordDO; +import cn.iocoder.yudao.module.system.service.rental.RentalItemsRecordService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - 租赁物品记录") +@RestController +@RequestMapping("/system/rental-items") +@Validated +public class RentalItemsRecordController { + + @Resource + private RentalItemsRecordService rentalItemsRecordService; + + @PostMapping("/create") + @Operation(summary = "创建租赁物品记录") + @PreAuthorize("@ss.hasPermission('system:rental-items:create')") + public CommonResult createRentalItemsRecord(@Valid @RequestBody RentalItemsRecordSaveReqVO createReqVO) { + return success(rentalItemsRecordService.createRentalItemsRecord(createReqVO)); + } + + @PostMapping("/createBatch") + @Operation(summary = "批量创建租赁物品记录") + @PreAuthorize("@ss.hasPermission('system:rental-items:create')") + public CommonResult createRentalItemsRecord(@Valid @RequestBody List createReqVO) { + rentalItemsRecordService.createRentalItemsRecordBath(createReqVO); + return success(true); + } + + @PutMapping("/update") + @Operation(summary = "更新租赁物品记录") + @PreAuthorize("@ss.hasPermission('system:rental-items:update')") + public CommonResult updateRentalItemsRecord(@Valid @RequestBody RentalItemsRecordSaveReqVO updateReqVO) { + rentalItemsRecordService.updateRentalItemsRecord(updateReqVO); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获取租赁物品记录") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:rental-items:query')") + public CommonResult getRentalItemsRecord(@RequestParam("id") Long id) { + + return success(BeanUtils.toBean(rentalItemsRecordService.getRentalItemsRecord(id), RentalItemsRecordRespVO.class)); + } + + @GetMapping("/page") + @Operation(summary = "获得租赁物品记录分页") + @PreAuthorize("@ss.hasPermission('system:rental-items:query')") + public CommonResult> getRentalItemsRecordPage(@Valid RentalItemsRecordPageReqVO pageReqVO) { + PageResult pageResult = rentalItemsRecordService.getRentalItemsRecordPage(pageReqVO); + return success(BeanUtils.toBean(pageResult, RentalItemsRecordRespVO.class)); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java new file mode 100644 index 00000000..9621d053 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java @@ -0,0 +1,108 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; +import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; +import cn.iocoder.yudao.module.system.service.rental.RentalCustomerService; +import cn.iocoder.yudao.module.system.service.rental.RentalDepositRecordService; +import cn.iocoder.yudao.module.system.service.rental.RentalOrderService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import javax.validation.Valid; +import java.io.IOException; +import java.math.BigDecimal; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; + + +@Tag(name = "管理后台 - 租赁订单") +@RestController +@RequestMapping("/system/rental-order") +@Validated +public class RentalOrderController { + + @Resource + private RentalOrderService rentalOrderService; + + @Resource + private RentalCustomerService rentalCustomerService; + + @Resource + private RentalDepositRecordService rentalDepositRecordService; + + @PostMapping("/create") + @Operation(summary = "创建租赁订单") + @PreAuthorize("@ss.hasPermission('system:rental-order:create')") + public CommonResult createRentalOrder(@Valid @RequestBody RentalOrderSaveReqVO createReqVO) { + return success(rentalOrderService.createRentalOrder(createReqVO)); + } + + @PutMapping("/update") + @Operation(summary = "更新租赁订单") + @PreAuthorize("@ss.hasPermission('system:rental-order:update')") + public CommonResult updateRentalOrder(@Valid @RequestBody RentalOrderSaveReqVO updateReqVO) { + return success(rentalOrderService.updateRentalOrder(updateReqVO)); + } + + @DeleteMapping("/delete") + @Operation(summary = "删除租赁订单") + @Parameter(name = "id", description = "编号", required = true) + @PreAuthorize("@ss.hasPermission('system:rental-order:delete')") + public CommonResult deleteRentalOrder(@RequestParam("id") Long id) { + rentalOrderService.deleteRentalOrder(id); + return success(true); + } + + @GetMapping("/get") + @Operation(summary = "获得租赁订单") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + @PreAuthorize("@ss.hasPermission('system:rental-order:query')") + public CommonResult getRentalOrder(@RequestParam("id") Long id) { + RentalOrderDO rentalOrder = rentalOrderService.getRentalOrder(id); + RentalOrderRespVO respVO = BeanUtils.toBean(rentalOrder, RentalOrderRespVO.class); + + // 获取客户详情 + RentalCustomerDO customerDO = rentalCustomerService.getRentalCustomer(rentalOrder.getCustomerId()); + if (customerDO != null) { + // 设置客户信息 + respVO.setCustomerName(customerDO.getName()); + respVO.setCustomerBankName(customerDO.getBankName()); + respVO.setCustomerBankNo(customerDO.getBankNo()); + } + + // 获取已收金额 + RentalDepositAmountReqVO amountReqVO = rentalDepositRecordService.getRentalDepositRecordAmount(rentalOrder.getOrderNo(), false); + // 设置已收金额 + respVO.setReceivedAmount(amountReqVO.getReceivedAmount()); + // 设置已退金额 + respVO.setRefundAmount(amountReqVO.getRefundAmount()); + + return success(respVO); + } + + @GetMapping("/page") + @Operation(summary = "获得租赁订单分页") + @PreAuthorize("@ss.hasPermission('system:rental-order:query')") + public CommonResult> getRentalOrderPage(@Valid RentalOrderPageReqVO pageReqVO) { + PageResult pageResult = rentalOrderService.getRentalOrderPage(pageReqVO); + return success(pageResult); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerPageReqVO.java new file mode 100644 index 00000000..3ec41554 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerPageReqVO.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租赁客户分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RentalCustomerPageReqVO extends PageParam { + + @Schema(description = "客户名称", example = "赵六") + private String name; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "开户行", example = "=") + private String bankName; + + @Schema(description = "卡号") + private String bankNo; + + @Schema(description = "剩余押金金额") + private BigDecimal amount; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerRespVO.java new file mode 100644 index 00000000..903b2d89 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerRespVO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租赁客户 Response VO") +@Data +public class RentalCustomerRespVO { + + @Schema(description = "租赁客户表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + private String name; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "开户行", requiredMode = Schema.RequiredMode.REQUIRED, example = "=") + private String bankName; + + @Schema(description = "卡号", requiredMode = Schema.RequiredMode.REQUIRED) + private String bankNo; + + @Schema(description = "剩余押金金额") + private BigDecimal amount; + + @Schema(description = "状态 | 0开启 1关闭") + private Integer status; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerSaveReqVO.java new file mode 100644 index 00000000..527e0cab --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerSaveReqVO.java @@ -0,0 +1,36 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 租赁客户新增/修改 Request VO") +@Data +public class RentalCustomerSaveReqVO { + + @Schema(description = "租赁客户表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "客户名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "赵六") + @NotEmpty(message = "客户名称不能为空") + private String name; + + @Schema(description = "手机号") + private String mobile; + + @Schema(description = "开户行", requiredMode = Schema.RequiredMode.REQUIRED, example = "=") + @NotEmpty(message = "开户行不能为空") + private String bankName; + + @Schema(description = "卡号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "卡号不能为空") + private String bankNo; + + @Schema(description = "剩余押金金额") + private BigDecimal amount; + + @Schema(description = "状态 | 0开启 1关闭") + private Integer status; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerStatusReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerStatusReqVO.java new file mode 100644 index 00000000..d1babf19 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/customer/RentalCustomerStatusReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 租赁客户新增/修改 Request VO") +@Data +public class RentalCustomerStatusReqVO { + + @Schema(description = "租赁客户表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "状态 | 0开启 1关闭") + private Integer status; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsCountReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsCountReqVO.java new file mode 100644 index 00000000..be1f259d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsCountReqVO.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 租赁物品数量 Request VO") +@Data +public class RentalItemsCountReqVO { + + @Schema(description = "租赁物品类型") + private Integer rentalItemsType; + + @Schema(description = "已租借数量") + private Integer number; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordPageReqVO.java new file mode 100644 index 00000000..003f17e2 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordPageReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租赁物品记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RentalItemsRecordPageReqVO extends PageParam { + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "租赁物品种类 | 字典值参考 system_rental_items_type") + private Integer rentalItemsType; + + @Schema(description = "类型 | 1租借 2归还") + private Integer type; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordRespVO.java new file mode 100644 index 00000000..227afce4 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordRespVO.java @@ -0,0 +1,30 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租赁物品记录 Response VO") +@Data +public class RentalItemsRecordRespVO { + + @Schema(description = "租赁订单表单主键") + private Long id; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "租赁物品种类 | 字典值参考 system_rental_items_type") + private Integer rentalItemsType; + + @Schema(description = "租赁数量") + private Integer number; + + @Schema(description = "类型 | 1租借 2归还") + private Integer type; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordSaveReqVO.java new file mode 100644 index 00000000..75858ad2 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/itemsrecord/RentalItemsRecordSaveReqVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 租赁物品记录新增/修改 Request VO") +@Data +public class RentalItemsRecordSaveReqVO { + + @Schema(description = "租赁订单表单主键") + private Long id; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "订单编号不能为空") + private String orderNo; + + @Schema(description = "租赁物品种类 | 字典值参考 system_rental_items_type", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "租赁物品种类不能为空") + private Integer rentalItemsType; + + @Schema(description = "租赁数量", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "租赁数量不能为空") + private Integer number; + + @Schema(description = "类型 | 1租借 2归还", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "类型不能为空") + private Integer type; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java new file mode 100644 index 00000000..b5346fe7 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.order; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租赁订单分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RentalOrderPageReqVO extends PageParam { + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "收款人") + private String recipient; + + @Schema(description = "客户编号") + private Long customerId; + + @Schema(description = "押金金额") + private Integer depositAmount; + + @Schema(description = "状态 | 1租赁中 2退款中 3已退") + private Integer status; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java new file mode 100644 index 00000000..b4baa774 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java @@ -0,0 +1,57 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.order; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - 租赁订单 Response VO") +@Data +public class RentalOrderRespVO { + + @Schema(description = "租赁订单表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "客户编号") + private Long customerId; + + @Schema(description = "客户名称") + private String customerName; + + @Schema(description = "客户开户行") + private String customerBankName; + + @Schema(description = "客户银行卡号") + private String customerBankNo; + + @Schema(description = "收款人") + private String recipient; + + @Schema(description = "押金金额") + private BigDecimal depositAmount; + + @Schema(description = "已收金额") + private BigDecimal receivedAmount; + + @Schema(description = "退款金额") + private BigDecimal refundAmount; + + @Schema(description = "扣款金额") + private BigDecimal chargebacksAmount; + + @Schema(description = "备注") + private String notes; + + @Schema(description = "状态 | 1租赁中 2退款中 3已退") + private Integer status; + + @Schema(description = "创建时间") + private LocalDateTime createTime; + + @Schema(description = "创建人姓名") + private String creatorName; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java new file mode 100644 index 00000000..93de6f0d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java @@ -0,0 +1,48 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.order; + +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.util.List; + +@Schema(description = "管理后台 - 租赁订单新增/修改 Request VO") +@Data +public class RentalOrderSaveReqVO { + + @Schema(description = "租赁订单表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "客户编号不能为空") + private Long customerId; + + @Schema(description = "收款人") + private String recipient; + + @Schema(description = "押金金额", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "押金金额不能为空") + private BigDecimal depositAmount; + + @Schema(description = "扣款金额") + private BigDecimal chargebacksAmount; + + @Schema(description = "备注") + private String notes; + + @Schema(description = "状态 | 1租赁中 2退款中 3已退") + private Integer status; + + @Schema(description = "租赁物品记录") + private List itemsRecords; + + @Schema(description = "租赁订单押金记录") + private List depositRecords; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositAmountReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositAmountReqVO.java new file mode 100644 index 00000000..828b2df5 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositAmountReqVO.java @@ -0,0 +1,17 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 押金金额 Request VO") +@Data +public class RentalDepositAmountReqVO { + + @Schema(description = "已收金额") + private BigDecimal receivedAmount; + + @Schema(description = "退款金额") + private BigDecimal refundAmount; +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordPageReqVO.java new file mode 100644 index 00000000..4d391fbd --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordPageReqVO.java @@ -0,0 +1,42 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND; + +@Schema(description = "管理后台 - 租赁订单押金记录分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class RentalDepositRecordPageReqVO extends PageParam { + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "支付方式 | 1支付宝 2微信 3银行卡") + private Integer paymentMethod; + + @Schema(description = "交易订单号") + private String transactionOrderNumber; + + @Schema(description = "收款/退款日期") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDate[] paymentDate; + + @Schema(description = "类型 | 1收款 2退款", example = "1") + private Integer type; + + @Schema(description = "创建时间") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND) + private LocalDateTime[] createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordRespVO.java new file mode 100644 index 00000000..7c04d37c --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordRespVO.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; + +@Schema(description = "管理后台 - 租赁订单押金记录 Response VO") +@Data +@ExcelIgnoreUnannotated +public class RentalDepositRecordRespVO { + + @Schema(description = "租赁订单押金记录表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @ExcelProperty("租赁订单押金记录表单主键") + private Long id; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("订单编号") + private String orderNo; + + @Schema(description = "支付方式 | 1支付宝 2微信 3银行卡", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("支付方式 | 1支付宝 2微信 3银行卡") + private Integer paymentMethod; + + @Schema(description = "交易订单号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("交易订单号") + private String transactionOrderNumber; + + @Schema(description = "银行卡号") + @ExcelProperty("银行卡号") + private String bankNo; + + @Schema(description = "客户银行卡号", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("客户银行卡号") + private String customerBankNo; + + @Schema(description = "收款/退款金额", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("收款/退款金额") + private BigDecimal amount; + + @Schema(description = "收款/退款日期", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("收款/退款日期") + private LocalDate paymentDate; + + @Schema(description = "类型 | 1收款 2退款", example = "1") + @ExcelProperty("类型 | 1收款 2退款") + private Integer type; + + @Schema(description = "附件信息") + @ExcelProperty("附件信息") + private List fileItems; + + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) + @ExcelProperty("创建时间") + private LocalDateTime createTime; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java new file mode 100644 index 00000000..3584c892 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +@Schema(description = "管理后台 - 租赁订单押金记录新增/修改 Request VO") +@Data +public class RentalDepositRecordSaveReqVO { + + @Schema(description = "租赁订单押金记录表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "订单编号不能为空") + private String orderNo; + + @Schema(description = "支付方式 | 1支付宝 2微信 3银行卡", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "支付方式 | 1支付宝 2微信 3银行卡不能为空") + private Integer paymentMethod; + + @Schema(description = "交易订单号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "交易订单号不能为空") + private String transactionOrderNumber; + + @Schema(description = "银行卡号") + private String bankNo; + + @Schema(description = "客户银行卡号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "客户银行卡号不能为空") + private String customerBankNo; + + @Schema(description = "收款/退款金额", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收款/退款金额不能为空") + private BigDecimal amount; + + @Schema(description = "收款/退款日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收款/退款日期不能为空") + private LocalDate paymentDate; + + @Schema(description = "类型 | 1收款 2退款", example = "1") + private Integer type; + + @Schema(description = "附件信息") + private List fileItems; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java index 4b3c3ee4..8bdb56bb 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/user/UserController.java @@ -181,6 +181,16 @@ public class UserController { return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap)); } + @PostMapping({"/list-by-deptIds"}) + @Operation(summary = "获取用户精简信息列表", description = "只包含被开启的用户,主要用于前端的下拉选项,无数据权限") + @DataPermission(enable = false) + public CommonResult> getAllUserList(@RequestBody List deptIds) { + List list = userService.getUserListByDepts(1, deptIds, CommonStatusEnum.ENABLE.getStatus()); + // 拼接数据 + Map deptMap = deptService.getDeptMap( + convertList(list, AdminUserDO::getDeptId)); + return success(UserConvert.INSTANCE.convertSimpleList(list, deptMap)); + } @PostMapping({"/list-all"}) @Operation(summary = "获取用户精简信息列表", description = "只包含被开启的用户,主要用于前端的下拉选项,无数据权限") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/project/ProjectDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/project/ProjectDO.java new file mode 100644 index 00000000..bd8c91c0 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/project/ProjectDO.java @@ -0,0 +1,94 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.project; + +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.time.LocalDate; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 项目管理 DO + * + * @author 符溶馨 + */ +@TableName(value = "system_project", autoResultMap = true) +@KeySequence("system_project_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class ProjectDO extends BaseDO { + + /** + * 项目管理表单主键 + */ + @TableId + private Long id; + /** + * 项目编号 + */ + private String projectNo; + /** + * 项目类型 | 字典值参考system_project_type + */ + private Integer type; + /** + * 项目名称 + */ + private String name; + /** + * 责任部门 + */ + private Long responsibleDept; + /** + * 参与部门集合 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set participationDept; + /** + * 责任人用户编号 + */ + private Long directorUserId; + /** + * 项目开始时间 + */ + private LocalDate startDate; + /** + * 项目结束时间 + */ + private LocalDate endDate; + /** + * 是否长期 | 0否 1是 + */ + private Integer isLongTerm; + /** + * 项目预算 + */ + private Integer projectBudget; + /** + * 项目内容 + */ + private String content; + /** + * 项目人员用户编号集合 + */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) + private Set staff; + /** + * 项目额外属性 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private Map dynamicAttribute; + /** + * 项目状态 | 1 进行中 2已完成 + */ + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalCustomerDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalCustomerDO.java new file mode 100644 index 00000000..33e5e265 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalCustomerDO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.rental; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +import java.math.BigDecimal; + +/** + * 租赁客户 DO + * + * @author 符溶馨 + */ +@TableName("system_rental_customer") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RentalCustomerDO extends BaseDO { + + /** + * 租赁客户表单主键 + */ + @TableId + private Long id; + /** + * 客户名称 + */ + private String name; + /** + * 手机号 + */ + private String mobile; + /** + * 开户行 + */ + private String bankName; + /** + * 卡号 + */ + private String bankNo; + /** + * 剩余押金金额 + */ + private BigDecimal amount; + + /** + * 状态 0开启 1关闭 + */ + private Integer status; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalDepositRecordDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalDepositRecordDO.java new file mode 100644 index 00000000..3744c117 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalDepositRecordDO.java @@ -0,0 +1,74 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.rental; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.KeySequence; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +/** + * 租赁订单押金记录 DO + * + * @author 符溶馨 + */ +@TableName(value = "system_rental_deposit_record", autoResultMap = true) +@KeySequence("system_rental_deposit_record_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。 +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RentalDepositRecordDO extends BaseDO { + + /** + * 租赁订单押金记录表单主键 + */ + @TableId + private Long id; + /** + * 订单编号 + */ + private String orderNo; + /** + * 支付方式 | 1支付宝 2微信 3银行卡 + */ + private Integer paymentMethod; + /** + * 交易订单号 + */ + private String transactionOrderNumber; + /** + * 银行卡号 + */ + private String bankNo; + /** + * 客户银行卡号 + */ + private String customerBankNo; + /** + * 收款/退款金额 + */ + private BigDecimal amount; + /** + * 收款/退款日期 + */ + private LocalDate paymentDate; + /** + * 类型 | 1收款 2退款 + */ + private Integer type; + /** + * 附件信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List fileItems; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalItemsRecordDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalItemsRecordDO.java new file mode 100644 index 00000000..d30adccf --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalItemsRecordDO.java @@ -0,0 +1,44 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.rental; + +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.*; + +/** + * 订单租赁物品记录 DO + * + * @author 符溶馨 + */ +@TableName("system_rental_items_record") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RentalItemsRecordDO extends BaseDO { + + /** + * 订单租赁物品记录表单主键 + */ + @TableId + private Long id; + /** + * 订单编号 + */ + private String orderNo; + /** + * 租赁物品种类 | 字典值参考 system_rental_items_type + */ + private Integer rentalItemsType; + /** + * 租赁数量 + */ + private Integer number; + /** + * 类型 | 1租借 2归还 + */ + private Integer type; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java new file mode 100644 index 00000000..08d415ae --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.system.dal.dataobject.rental; + +import lombok.*; + +import java.math.BigDecimal; +import java.util.*; +import java.time.LocalDateTime; +import java.time.LocalDateTime; +import com.baomidou.mybatisplus.annotation.*; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; + +/** + * 租赁订单 DO + * + * @author 符溶馨 + */ +@TableName("system_rental_order") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class RentalOrderDO extends BaseDO { + + /** + * 租赁订单表单主键 + */ + @TableId + private Long id; + /** + * 订单编号 + */ + private String orderNo; + /** + * 客户编号 + */ + private Long customerId; + /** + * 收款人 + */ + private String recipient; + /** + * 押金金额 + */ + private BigDecimal depositAmount; + /** + * 扣款金额 + */ + private BigDecimal chargebacksAmount; + /** + * 备注 + */ + private String notes; + /** + * 状态 | 1租赁中 2退款中 3已退 + */ + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java new file mode 100644 index 00000000..134f819b --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/project/ProjectMapper.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.dal.mysql.project; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 项目管理 Mapper + * + * @author 符溶馨 + */ +@Mapper +public interface ProjectMapper extends BaseMapperX { + + default PageResult selectPage(ProjectPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(ProjectDO::getProjectNo, reqVO.getProjectNo()) + .eqIfPresent(ProjectDO::getType, reqVO.getType()) + .likeIfPresent(ProjectDO::getName, reqVO.getName()) + .eqIfPresent(ProjectDO::getResponsibleDept, reqVO.getResponsibleDept()) + .likeIfPresent(ProjectDO::getParticipationDept, reqVO.getParticipationDept()) + .eqIfPresent(ProjectDO::getDirectorUserId, reqVO.getDirectorUserId()) + .betweenIfPresent(ProjectDO::getStartDate, reqVO.getStartDate()) + .betweenIfPresent(ProjectDO::getEndDate, reqVO.getEndDate()) + .eqIfPresent(ProjectDO::getIsLongTerm, reqVO.getIsLongTerm()) + .eqIfPresent(ProjectDO::getStatus, reqVO.getStatus()) + .orderByDesc(ProjectDO::getId)); + } +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalCustomerMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalCustomerMapper.java new file mode 100644 index 00000000..1b3b82c8 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalCustomerMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.dal.mysql.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import org.apache.ibatis.annotations.Mapper; + +/** + * 租赁客户 Mapper + * + * @author 符溶馨 + */ +@Mapper +public interface RentalCustomerMapper extends BaseMapperX { + + default PageResult selectPage(RentalCustomerPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .likeIfPresent(RentalCustomerDO::getName, reqVO.getName()) + .eqIfPresent(RentalCustomerDO::getMobile, reqVO.getMobile()) + .likeIfPresent(RentalCustomerDO::getBankName, reqVO.getBankName()) + .eqIfPresent(RentalCustomerDO::getBankNo, reqVO.getBankNo()) + .eqIfPresent(RentalCustomerDO::getAmount, reqVO.getAmount()) + .betweenIfPresent(RentalCustomerDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(RentalCustomerDO::getId)); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalDepositRecordMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalDepositRecordMapper.java new file mode 100644 index 00000000..5b0e7bea --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalDepositRecordMapper.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.dal.mysql.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; + +/** + * 租赁订单押金记录 Mapper + * + * @author 符溶馨 + */ +@Mapper +public interface RentalDepositRecordMapper extends BaseMapperX { + + default PageResult selectPage(RentalDepositRecordPageReqVO reqVO) { + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(RentalDepositRecordDO::getOrderNo, reqVO.getOrderNo()) + .eqIfPresent(RentalDepositRecordDO::getPaymentMethod, reqVO.getPaymentMethod()) + .eqIfPresent(RentalDepositRecordDO::getTransactionOrderNumber, reqVO.getTransactionOrderNumber()) + .betweenIfPresent(RentalDepositRecordDO::getPaymentDate, reqVO.getPaymentDate()) + .eqIfPresent(RentalDepositRecordDO::getType, reqVO.getType()) + .betweenIfPresent(RentalDepositRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(RentalDepositRecordDO::getCreateTime)); + } + + RentalDepositAmountReqVO selectAmount(@Param("orderNo") String orderNo, + @Param("isUpdate") Boolean isUpdate); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java new file mode 100644 index 00000000..76356d45 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.dal.mysql.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsCountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordPageReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalItemsRecordDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; +import java.util.List; + +@Mapper +public interface RentalItemsRecordMapper extends BaseMapperX { + + default PageResult selectPage(RentalItemsRecordPageReqVO reqVO) { + + return selectPage(reqVO, new LambdaQueryWrapperX() + .eqIfPresent(RentalItemsRecordDO::getOrderNo, reqVO.getOrderNo()) + .eqIfPresent(RentalItemsRecordDO::getRentalItemsType, reqVO.getRentalItemsType()) + .eqIfPresent(RentalItemsRecordDO::getType, reqVO.getType()) + .betweenIfPresent(RentalItemsRecordDO::getCreateTime, reqVO.getCreateTime()) + .orderByDesc(RentalItemsRecordDO::getCreateTime)); + } + + List selectRentalItemsCount(@Param("orderNo") String orderNo); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalOrderMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalOrderMapper.java new file mode 100644 index 00000000..bfc9cd2b --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalOrderMapper.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.system.dal.mysql.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; + +/** + * 租赁订单 Mapper + * + * @author 符溶馨 + */ +@Mapper +public interface RentalOrderMapper extends BaseMapperX { + + default PageResult selectPage(RentalOrderPageReqVO reqVO) { + + MPJLambdaWrapperX queryWrapper = new MPJLambdaWrapperX<>(); + queryWrapper.selectAll(RentalOrderDO.class); + queryWrapper.selectAs(RentalCustomerDO::getName, RentalOrderRespVO::getCustomerName); + queryWrapper.selectAs("SUM( CASE WHEN deposit.type = 1 THEN deposit.amount END )", RentalOrderRespVO::getReceivedAmount); + queryWrapper.selectAs("SUM( CASE WHEN deposit.type = 2 THEN deposit.amount END )", RentalOrderRespVO::getRefundAmount); + queryWrapper.selectAs(AdminUserDO::getNickname, RentalOrderRespVO::getCreatorName); + queryWrapper.leftJoin(RentalDepositRecordDO.class, "deposit", RentalDepositRecordDO::getOrderNo, RentalOrderDO::getOrderNo); + queryWrapper.leftJoin(AdminUserDO.class, AdminUserDO::getId, RentalOrderDO::getCreator); + queryWrapper.leftJoin(RentalCustomerDO.class, RentalCustomerDO::getId, RentalOrderDO::getCustomerId); + queryWrapper.eqIfPresent(RentalOrderDO::getOrderNo, reqVO.getOrderNo()) + .eqIfPresent(RentalOrderDO::getCustomerId, reqVO.getCustomerId()) + .eqIfPresent(RentalOrderDO::getDepositAmount, reqVO.getDepositAmount()) + .eqIfPresent(RentalOrderDO::getStatus, reqVO.getStatus()) + .likeIfPresent(RentalOrderDO::getRecipient, reqVO.getRecipient()) + .betweenIfPresent(RentalOrderDO::getCreateTime, reqVO.getCreateTime()) + .groupBy(RentalOrderDO::getOrderNo) + .orderByDesc(RentalOrderDO::getCreateTime); + + return selectJoinPage(reqVO, RentalOrderRespVO.class, queryWrapper); + } + + BigDecimal selectOrderAmount(@Param("orderNo") String orderNo); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java index fc6a6220..24ad2f37 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/redis/RedisKeyConstants.java @@ -98,4 +98,11 @@ public interface RedisKeyConstants { * VALUE 数据格式:String 模版信息 */ String SMS_TEMPLATE = "sms_template"; + + /** + * 租赁订单剩余押金金额的缓存 + * KEY 格式:rental_order_amount:{orderNo} + * VALUE 数据格式:String 剩余金额 + */ + String RENTAL_ORDER_AMOUNT = "rental_order_amount"; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java new file mode 100644 index 00000000..bf942b7d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectService.java @@ -0,0 +1,55 @@ +package cn.iocoder.yudao.module.system.service.project; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; + +import javax.validation.Valid; + +/** + * 项目管理 Service 接口 + * + * @author 符溶馨 + */ +public interface ProjectService { + + /** + * 创建项目管理 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProject(@Valid ProjectSaveReqVO createReqVO); + + /** + * 更新项目管理 + * + * @param updateReqVO 更新信息 + */ + void updateProject(@Valid ProjectSaveReqVO updateReqVO); + + /** + * 删除项目管理 + * + * @param id 编号 + */ + void deleteProject(Long id); + + /** + * 获得项目管理 + * + * @param id 编号 + * @return 项目管理 + */ + ProjectDO getProject(Long id); + + /** + * 获得项目管理分页 + * + * @param pageReqVO 分页查询 + * @return 项目管理分页 + */ + PageResult getProjectPage(ProjectPageReqVO pageReqVO); + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java new file mode 100644 index 00000000..faf15d46 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/project/ProjectServiceImpl.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.system.service.project; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.project.ProjectDO; +import cn.iocoder.yudao.module.system.dal.mysql.project.ProjectMapper; +import com.baomidou.mybatisplus.core.toolkit.IdWorker; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.PROJECT_NOT_EXISTS; + +/** + * 项目管理 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +public class ProjectServiceImpl implements ProjectService { + + @Resource + private ProjectMapper projectMapper; + + @Override + public Long createProject(ProjectSaveReqVO createReqVO) { + // 插入 + ProjectDO project = BeanUtils.toBean(createReqVO, ProjectDO.class); + project.setProjectNo(IdWorker.getIdStr()); + projectMapper.insert(project); + // 返回 + return project.getId(); + } + + @Override + public void updateProject(ProjectSaveReqVO updateReqVO) { + // 校验存在 + validateProjectExists(updateReqVO.getId()); + // 更新 + ProjectDO updateObj = BeanUtils.toBean(updateReqVO, ProjectDO.class); + projectMapper.updateById(updateObj); + } + + @Override + public void deleteProject(Long id) { + // 校验存在 + validateProjectExists(id); + // 删除 + projectMapper.deleteById(id); + } + + private void validateProjectExists(Long id) { + if (projectMapper.selectById(id) == null) { + throw exception(PROJECT_NOT_EXISTS); + } + } + + @Override + public ProjectDO getProject(Long id) { + return projectMapper.selectById(id); + } + + @Override + public PageResult getProjectPage(ProjectPageReqVO pageReqVO) { + return projectMapper.selectPage(pageReqVO); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerService.java new file mode 100644 index 00000000..c49cb2b5 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerService.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerStatusReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; + +import javax.validation.Valid; +import java.util.List; + +/** + * 租赁客户 Service 接口 + * + * @author 符溶馨 + */ +public interface RentalCustomerService { + + /** + * 创建租赁客户 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createRentalCustomer(@Valid RentalCustomerSaveReqVO createReqVO); + + /** + * 更新租赁客户 + * + * @param updateReqVO 更新信息 + */ + void updateRentalCustomer(@Valid RentalCustomerSaveReqVO updateReqVO); + + /** + * 更新租赁客户状态 + * @param updateReqVO 更新信息 + */ + void updateRentalCustomerStatus(RentalCustomerStatusReqVO updateReqVO); + + /** + * 删除租赁客户 + * + * @param id 编号 + */ + void deleteRentalCustomer(Long id); + + /** + * 获得租赁客户 + * + * @param id 编号 + * @return 租赁客户 + */ + RentalCustomerDO getRentalCustomer(Long id); + + /** + * 获得租赁客户分页 + * + * @param pageReqVO 分页查询 + * @return 租赁客户分页 + */ + PageResult getRentalCustomerPage(RentalCustomerPageReqVO pageReqVO); + + /** + * 获得租赁客户列表 + * @return 租赁客户列表 + */ + List getRentalCustomerList(); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerServiceImpl.java new file mode 100644 index 00000000..071a1b2c --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalCustomerServiceImpl.java @@ -0,0 +1,91 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerStatusReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalCustomerDO; +import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalCustomerMapper; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; + +import java.util.List; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_CUSTOMER_NOT_EXISTS; + +/** + * 租赁客户 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +public class RentalCustomerServiceImpl implements RentalCustomerService { + + @Resource + private RentalCustomerMapper rentalCustomerMapper; + + @Override + public Long createRentalCustomer(RentalCustomerSaveReqVO createReqVO) { + // 插入 + RentalCustomerDO rentalCustomer = BeanUtils.toBean(createReqVO, RentalCustomerDO.class); + rentalCustomer.setStatus(CommonStatusEnum.ENABLE.getStatus()); + rentalCustomerMapper.insert(rentalCustomer); + // 返回 + return rentalCustomer.getId(); + } + + @Override + public void updateRentalCustomer(RentalCustomerSaveReqVO updateReqVO) { + // 校验存在 + validateRentalCustomerExists(updateReqVO.getId()); + // 更新 + RentalCustomerDO updateObj = BeanUtils.toBean(updateReqVO, RentalCustomerDO.class); + rentalCustomerMapper.updateById(updateObj); + } + + @Override + public void updateRentalCustomerStatus(RentalCustomerStatusReqVO updateReqVO) { + // 校验存在 + validateRentalCustomerExists(updateReqVO.getId()); + // 更新 + RentalCustomerDO updateObj = BeanUtils.toBean(updateReqVO, RentalCustomerDO.class); + rentalCustomerMapper.updateById(updateObj); + } + + @Override + public void deleteRentalCustomer(Long id) { + // 校验存在 + validateRentalCustomerExists(id); + // 删除 + rentalCustomerMapper.deleteById(id); + } + + private void validateRentalCustomerExists(Long id) { + if (rentalCustomerMapper.selectById(id) == null) { + throw exception(RENTAL_CUSTOMER_NOT_EXISTS); + } + } + + @Override + public RentalCustomerDO getRentalCustomer(Long id) { + return rentalCustomerMapper.selectById(id); + } + + @Override + public PageResult getRentalCustomerPage(RentalCustomerPageReqVO pageReqVO) { + return rentalCustomerMapper.selectPage(pageReqVO); + } + + @Override + public List getRentalCustomerList() { + return rentalCustomerMapper.selectList(RentalCustomerDO::getStatus, CommonStatusEnum.ENABLE.getStatus()); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordService.java new file mode 100644 index 00000000..cb8a66ec --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordService.java @@ -0,0 +1,64 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.List; + +/** + * 租赁订单押金记录 Service 接口 + * + * @author 符溶馨 + */ +public interface RentalDepositRecordService { + + /** + * 创建租赁订单押金记录 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createRentalDepositRecord(@Valid RentalDepositRecordSaveReqVO createReqVO); + + /** + * 批量创建租赁订单押金记录 + * + * @param createReqVO 创建信息 + */ + void createRentalDepositRecordBatch(@Valid List createReqVO); + + /** + * 更新租赁订单押金记录 + * + * @param updateReqVO 更新信息 + */ + void updateRentalDepositRecord(@Valid RentalDepositRecordSaveReqVO updateReqVO); + + /** + * 获得租赁订单押金记录 + * + * @param id 编号 + * @return 租赁订单押金记录 + */ + RentalDepositRecordDO getRentalDepositRecord(Long id); + + /** + * 获得租赁订单押金记录分页 + * + * @param pageReqVO 分页查询 + * @return 租赁订单押金记录分页 + */ + PageResult getRentalDepositRecordPage(RentalDepositRecordPageReqVO pageReqVO); + + /** + * 获得指定订单的已收取的押金金额 + * @param orderNo 订单编号 + * @return 数量 + */ + RentalDepositAmountReqVO getRentalDepositRecordAmount(String orderNo, Boolean isUpdate); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java new file mode 100644 index 00000000..9ae839bd --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java @@ -0,0 +1,129 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.infra.api.file.FileApi; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalDepositRecordMapper; +import org.springframework.context.annotation.Lazy; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.List; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; + +/** + * 租赁订单押金记录 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +public class RentalDepositRecordServiceImpl implements RentalDepositRecordService { + + @Resource + private RentalDepositRecordMapper rentalDepositRecordMapper; + + @Resource + @Lazy + private RentalOrderService rentalOrderService; + + @Resource + private FileApi fileApi; + + @Override + public Long createRentalDepositRecord(RentalDepositRecordSaveReqVO createReqVO) { + + // 获取当前订单的 剩余押金金额 + BigDecimal depositAmount = rentalOrderService.getOrderAmount(createReqVO.getOrderNo()); + + // 获取当前订单的金额 + RentalDepositAmountReqVO reqVO = getRentalDepositRecordAmount(createReqVO.getOrderNo(), true); + // 已收金额 - 退款金额 + BigDecimal amount = reqVO.getReceivedAmount().subtract(reqVO.getRefundAmount()); + + switch (createReqVO.getType()) { + case 1: + // 押金收款 + // 判断实际已收的金额 + 本次收款金额 大于 当前订单的剩余押金金额时 + if (amount.add(createReqVO.getAmount()).compareTo(depositAmount) > 0) { + throw exception(RENTAL_RECEIVED_AMOUNT_EXCESS); + } + break; + case 2: + // 押金退款 + // 判断当前退款金额 大于 实际已收的金额时 + if (amount.compareTo(createReqVO.getAmount()) < 0) { + throw exception(RENTAL_REFUND_AMOUNT_EXCESS); + } + break; + } + + // 插入 + RentalDepositRecordDO rentalDepositRecord = BeanUtils.toBean(createReqVO, RentalDepositRecordDO.class); + rentalDepositRecordMapper.insert(rentalDepositRecord); + + // 更新交易凭证附件 业务编号 + UpdateBusinessFile(rentalDepositRecord); + // 返回 + return rentalDepositRecord.getId(); + } + + @Override + public void createRentalDepositRecordBatch(List createReqVO) { + // 插入 + List rentalDepositRecord = BeanUtils.toBean(createReqVO, RentalDepositRecordDO.class); + rentalDepositRecordMapper.insertBatch(rentalDepositRecord); + + for (RentalDepositRecordDO record : rentalDepositRecord) { + // 更新交易凭证附件 业务编号 + UpdateBusinessFile(record); + } + } + + private void UpdateBusinessFile(RentalDepositRecordDO updateReqVO) { + + List urls = updateReqVO.getFileItems().stream().map(UploadUserFile::getUrl).collect(Collectors.toList()); + fileApi.updateBusinessFile(urls, updateReqVO.getId().toString()); + } + + @Override + public void updateRentalDepositRecord(RentalDepositRecordSaveReqVO updateReqVO) { + // 校验存在 + validateRentalDepositRecordExists(updateReqVO.getId()); + // 更新 + RentalDepositRecordDO updateObj = BeanUtils.toBean(updateReqVO, RentalDepositRecordDO.class); + rentalDepositRecordMapper.updateById(updateObj); + } + + private void validateRentalDepositRecordExists(Long id) { + if (rentalDepositRecordMapper.selectById(id) == null) { + throw exception(RENTAL_DEPOSIT_RECORD_NOT_EXISTS); + } + } + + @Override + public RentalDepositRecordDO getRentalDepositRecord(Long id) { + return rentalDepositRecordMapper.selectById(id); + } + + @Override + public PageResult getRentalDepositRecordPage(RentalDepositRecordPageReqVO pageReqVO) { + return rentalDepositRecordMapper.selectPage(pageReqVO); + } + + @Override + public RentalDepositAmountReqVO getRentalDepositRecordAmount(String orderNo, Boolean isUpdate) { + return rentalDepositRecordMapper.selectAmount(orderNo, isUpdate); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java new file mode 100644 index 00000000..53253125 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java @@ -0,0 +1,60 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsCountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalItemsRecordDO; +import io.swagger.v3.oas.models.security.SecurityScheme; + +import javax.validation.Valid; +import java.util.List; + +/** + * 租赁物品记录 Service 接口 + * + * @author 符溶馨 + */ +public interface RentalItemsRecordService { + + /** + * 创建租赁物品记录 + * @param createReqVO 创建信息 + */ + Long createRentalItemsRecord(@Valid RentalItemsRecordSaveReqVO createReqVO); + + /** + * 创建租赁物品记录 + * @param createReqVO 创建信息 + */ + void createRentalItemsRecordBath(@Valid List createReqVO); + + /** + * 更新租赁物品记录 + * @param updateReqVO 更新信息 + */ + void updateRentalItemsRecord(@Valid RentalItemsRecordSaveReqVO updateReqVO); + + /** + * 查询租赁物品记录 + * @param id id + * @return 租赁物品记录 + */ + RentalItemsRecordDO getRentalItemsRecord(Long id); + + /** + * 分页查询租赁物品记录 + * @param pageReqVO 分页参数 + * @return 租赁物品记录列表 + */ + PageResult getRentalItemsRecordPage(RentalItemsRecordPageReqVO pageReqVO); + + /** + * 获取指定订单指定类型的租赁物品的剩余数量 + * @param orderNo 订单编号 + * @return 剩余数量 + */ + List getRentalItemsCount(String orderNo); +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java new file mode 100644 index 00000000..3301cd6d --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java @@ -0,0 +1,111 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsCountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalItemsRecordDO; +import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalItemsRecordMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_ITEMS_NUMBER_EXCESS; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_ITEMS_RECORD_NOT_EXISTS; + +/** + * 租赁物品记录 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +@Slf4j +public class RentalItemsRecordServiceImpl implements RentalItemsRecordService{ + + @Resource + private RentalItemsRecordMapper rentalItemsRecordMapper; + + @Override + @Transactional(rollbackFor = Exception.class) + public Long createRentalItemsRecord(RentalItemsRecordSaveReqVO createReqVO) { + + // 获取订单剩余租借数量 使用悲观锁 + List reqVOS = getRentalItemsCount(createReqVO.getOrderNo()); + Map countMap = convertMap(reqVOS, RentalItemsCountReqVO::getRentalItemsType); + + // 判断租借类型为归还时,检验归还数量是否大于剩余数量 + if (createReqVO.getType() == 2 && countMap.get(createReqVO.getRentalItemsType()).getNumber() < createReqVO.getNumber()) { + throw exception(RENTAL_ITEMS_NUMBER_EXCESS); + } + + RentalItemsRecordDO createDO = BeanUtils.toBean(createReqVO, RentalItemsRecordDO.class); + rentalItemsRecordMapper.insert(createDO); + + return createDO.getId(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void createRentalItemsRecordBath(List createReqVO) { + + // 获取订单剩余租借数量 使用悲观锁 + List reqVOS = getRentalItemsCount(createReqVO.get(0).getOrderNo()); + Map countMap = convertMap(reqVOS, RentalItemsCountReqVO::getRentalItemsType); + + for (RentalItemsRecordSaveReqVO vo : createReqVO) { + + // 判断租借类型为归还时,检验归还数量是否大于剩余数量 + if (vo.getType() == 2) { + + if (countMap.get(vo.getRentalItemsType()) != null && + countMap.get(vo.getRentalItemsType()).getNumber() < vo.getNumber()) { + throw exception(RENTAL_ITEMS_NUMBER_EXCESS); + } + } + } + + List createReq = BeanUtils.toBean(createReqVO, RentalItemsRecordDO.class); + rentalItemsRecordMapper.insertBatch(createReq); + } + + @Override + public void updateRentalItemsRecord(RentalItemsRecordSaveReqVO updateReqVO) { + + // 校验存在 + validateRentalItemsRecordExists(updateReqVO.getId()); + + RentalItemsRecordDO updateObj = BeanUtils.toBean(updateReqVO, RentalItemsRecordDO.class); + rentalItemsRecordMapper.updateById(updateObj); + } + + @Override + public RentalItemsRecordDO getRentalItemsRecord(Long id) { + return rentalItemsRecordMapper.selectById(id); + } + + @Override + public PageResult getRentalItemsRecordPage(RentalItemsRecordPageReqVO pageReqVO) { + return rentalItemsRecordMapper.selectPage(pageReqVO); + } + + @Override + public List getRentalItemsCount(String orderNo) { + + return rentalItemsRecordMapper.selectRentalItemsCount(orderNo); + } + + private void validateRentalItemsRecordExists(Long id) { + if (rentalItemsRecordMapper.selectById(id) == null) { + throw exception(RENTAL_ITEMS_RECORD_NOT_EXISTS); + } + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java new file mode 100644 index 00000000..c42cec47 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java @@ -0,0 +1,63 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; + +import javax.validation.Valid; +import java.math.BigDecimal; + +/** + * 租赁订单 Service 接口 + * + * @author 符溶馨 + */ +public interface RentalOrderService { + + /** + * 创建租赁订单 + * + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createRentalOrder(@Valid RentalOrderSaveReqVO createReqVO); + + /** + * 更新租赁订单 + * + * @param updateReqVO 更新信息 + */ + BigDecimal updateRentalOrder(@Valid RentalOrderSaveReqVO updateReqVO); + + /** + * 删除租赁订单 + * + * @param id 编号 + */ + void deleteRentalOrder(Long id); + + /** + * 获得租赁订单 + * + * @param id 编号 + * @return 租赁订单 + */ + RentalOrderDO getRentalOrder(Long id); + + /** + * 获得租赁订单分页 + * + * @param pageReqVO 分页查询 + * @return 租赁订单分页 + */ + PageResult getRentalOrderPage(RentalOrderPageReqVO pageReqVO); + + /** + * 获取订单的剩余押金金额(押金金额-扣款金额) + * @param orderNo 订单编号 + * @return 剩余押金金额 + */ + BigDecimal getOrderAmount(String orderNo); +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java new file mode 100644 index 00000000..221fc2ab --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java @@ -0,0 +1,148 @@ +package cn.iocoder.yudao.module.system.service.rental; + +import cn.hutool.core.collection.CollectionUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; +import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalOrderMapper; +import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import lombok.extern.slf4j.Slf4j; +import org.redisson.api.RLock; +import org.redisson.api.RedissonClient; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_ORDER_NOT_EXISTS; + +/** + * 租赁订单 Service 实现类 + * + * @author 符溶馨 + */ +@Service +@Validated +@Slf4j +public class RentalOrderServiceImpl implements RentalOrderService { + + @Resource + private RentalOrderMapper rentalOrderMapper; + + @Resource + @Lazy + private RentalItemsRecordService rentalItemsRecordService; + + @Resource + @Lazy + private RentalDepositRecordService rentalDepositRecordService; + + @Resource + private RedissonClient redissonClient; + + @Resource + private StringRedisTemplate stringRedisTemplate; + + @Override + public Long createRentalOrder(RentalOrderSaveReqVO createReqVO) { + // 新增订单DO + RentalOrderDO rentalOrder = BeanUtils.toBean(createReqVO, RentalOrderDO.class); + + // 获取当前日期 + String now = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")); + // 获取分布式锁 + String LOCK_KEY = "lock:rental:order:create"; + RLock lock = redissonClient.getLock(LOCK_KEY); + try { + lock.lock(); + // redis 获取当天订单号 + String no = stringRedisTemplate.opsForValue().get(now); + if (no != null) { + no = "ZL" + now + String.format("%03d", Integer.parseInt(no) + 1); + // redis 缓存订单号 + stringRedisTemplate.opsForValue().increment(now, 1); + }else { + no = "ZL" + now + String.format("%03d", 1); + // redis 缓存订单号 + stringRedisTemplate.opsForValue().set(now, "1", 1, TimeUnit.DAYS); + } + // 设置订单编号 + rentalOrder.setOrderNo(no); + createReqVO.getDepositRecords().forEach(item -> item.setOrderNo(rentalOrder.getOrderNo())); + createReqVO.getItemsRecords().forEach(item -> item.setOrderNo(rentalOrder.getOrderNo())); + } catch (Exception ex) { + log.error("[messageResend][执行异常]", ex); + } finally { + lock.unlock(); + } + + // 插入订单 + rentalOrderMapper.insert(rentalOrder); + + // 同步插入租赁物品记录 + rentalItemsRecordService.createRentalItemsRecordBath(createReqVO.getItemsRecords()); + if (CollectionUtil.isNotEmpty(createReqVO.getDepositRecords())) { + // 同步插入租赁押金记录 + rentalDepositRecordService.createRentalDepositRecordBatch(createReqVO.getDepositRecords()); + } + + // 返回 + return rentalOrder.getId(); + } + + @Override + @CachePut(value = RedisKeyConstants.RENTAL_ORDER_AMOUNT, key = "#updateReqVO.orderNo", condition = "#updateReqVO.status == 1") + public BigDecimal updateRentalOrder(RentalOrderSaveReqVO updateReqVO) { + // 校验存在 + validateRentalOrderExists(updateReqVO.getId()); + // 更新 + RentalOrderDO updateObj = BeanUtils.toBean(updateReqVO, RentalOrderDO.class); + rentalOrderMapper.updateById(updateObj); + + return updateObj.getDepositAmount().subtract(updateObj.getChargebacksAmount() == null ? BigDecimal.ZERO : updateObj.getChargebacksAmount()); + } + + @Override + public void deleteRentalOrder(Long id) { + // 校验存在 + validateRentalOrderExists(id); + // 删除 + rentalOrderMapper.deleteById(id); + } + + private void validateRentalOrderExists(Long id) { + if (rentalOrderMapper.selectById(id) == null) { + throw exception(RENTAL_ORDER_NOT_EXISTS); + } + } + + @Override + public RentalOrderDO getRentalOrder(Long id) { + return rentalOrderMapper.selectById(id); + } + + @Override + public PageResult getRentalOrderPage(RentalOrderPageReqVO pageReqVO) { + return rentalOrderMapper.selectPage(pageReqVO); + } + + @Override + @Cacheable(value = RedisKeyConstants.RENTAL_ORDER_AMOUNT, key = "#orderNo", unless = "#result == null") + public BigDecimal getOrderAmount(String orderNo) { + return rentalOrderMapper.selectOrderAmount(orderNo); + } + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java index f4585e65..a80f5c96 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserService.java @@ -413,4 +413,13 @@ public interface AdminUserService { * @param entryDate */ void updateUserEntryDate(Long id, LocalDateTime entryDate); + + /** + * 获取指定部门下的用户信息 + * @param userType 用户类型 + * @param deptIds 部门列表 + * @param status 用户状态 + * @return 用户列表 + */ + List getUserListByDepts(Integer userType, List deptIds, Integer status); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index 13bca1e4..0defd5f1 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -810,4 +810,12 @@ public class AdminUserServiceImpl implements AdminUserService { public void updateUserEntryDate(Long id, LocalDateTime entryDate) { userMapper.updateById(new AdminUserDO().setId(id).setEntryDate(entryDate)); } + + @Override + public List getUserListByDepts(Integer userType, List deptIds, Integer status) { + return userMapper.selectList(new LambdaQueryWrapperX() + .eqIfPresent(AdminUserDO::getUserType, userType) + .eqIfPresent(AdminUserDO::getStatus, status) + .inIfPresent(AdminUserDO::getDeptId, deptIds)); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalDepositRecordMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalDepositRecordMapper.xml new file mode 100644 index 00000000..7d657777 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalDepositRecordMapper.xml @@ -0,0 +1,25 @@ + + + + + + + + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml new file mode 100644 index 00000000..0abb1b9b --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalOrderMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalOrderMapper.xml new file mode 100644 index 00000000..b75b1cde --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalOrderMapper.xml @@ -0,0 +1,21 @@ + + + + + + + + From b8da3af92d3df2d1e2c7904731b2baf16cadfd25 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sat, 23 Nov 2024 11:33:11 +0800 Subject: [PATCH 09/18] =?UTF-8?q?feat(bpm):=20=E6=B7=BB=E5=8A=A0=20OA=20?= =?UTF-8?q?=E9=80=80=E6=AC=BE=E7=94=B3=E8=AF=B7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增退款申请相关的数据结构和接口 - 实现退款申请的创建、查询和结果更新功能 - 添加退款申请的监听器,用于处理流程实例结果事件 - 定义退款申请相关的错误码 --- .../module/bpm/enums/ErrorCodeConstants.java | 2 + .../admin/oa/BpmOARefundController.java | 62 +++++++++ .../oa/vo/refund/BpmOARefundCreateReqVO.java | 58 +++++++++ .../admin/oa/vo/refund/BpmOARefundItems.java | 15 +++ .../admin/oa/vo/refund/BpmOARefundRespVO.java | 51 ++++++++ .../bpm/dal/dataobject/oa/BpmOARefundDO.java | 56 +++++++++ .../bpm/dal/mysql/oa/BpmOARefundMapper.java | 9 ++ .../bpm/service/oa/BpmOARefundService.java | 41 ++++++ .../service/oa/BpmOARefundServiceImpl.java | 118 ++++++++++++++++++ .../listener/BpmOARefundResultListener.java | 32 +++++ 10 files changed, 444 insertions(+) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOARefundController.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundCreateReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundItems.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOARefundMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundService.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOARefundResultListener.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index c3e9d232..ed08ccde 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -57,6 +57,8 @@ public interface ErrorCodeConstants { ErrorCode OA_EVECTION_IS_EXISTS = new ErrorCode(1_009_001_120, "该时间段您正在出差!请重新选择正确出差时间。"); ErrorCode OA_INVOICE_NOT_EXISTS = new ErrorCode(1_009_001_121, "开票申请不存在"); ErrorCode OA_REPLACEMENT_CARD_NOT_EXISTS = new ErrorCode(1_009_001_122, "补卡申请不存在"); + ErrorCode OA_REFUND_CARD_NOT_EXISTS = new ErrorCode(1_009_001_123, "退款申请不存在"); + // ========== 流程模型 1-009-002-000 ========== ErrorCode MODEL_KEY_EXISTS = new ErrorCode(1_009_002_000, "已经存在流程标识为【{}】的流程"); diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOARefundController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOARefundController.java new file mode 100644 index 00000000..ea5a9a17 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOARefundController.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund.BpmOARefundCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund.BpmOARefundRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOARefundDO; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOARefundService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * OA 退款申请 Controller + * + * @author 符溶馨 + + */ +@Tag(name = "管理后台 - OA 退款申请") +@RestController +@RequestMapping("/bpm/oa/refund") +@Validated +public class BpmOARefundController { + + @Resource + private BpmOARefundService refundService; + + @PostMapping("/create") + @Operation(summary = "创建请求申请") + public CommonResult createRefund(@Valid @RequestBody BpmOARefundCreateReqVO createReqVO) { + + return success(refundService.createRefund(getLoginUserId(), createReqVO)); + } + + @GetMapping("/get") + @Operation(summary = "获得退款申请") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getRefund(@RequestParam("id") Long id) { + + BpmOARefundDO refund = refundService.getRefund(id); + + return success(BeanUtils.toBean(refund, BpmOARefundRespVO.class)); + } + + @GetMapping("/getByProcessInstanceId") + @Operation(summary = "获得退款申请") + @Parameter(name = "processInstanceId", description = "流程实例编号", required = true, example = "1024") + public CommonResult getByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) { + + BpmOARefundDO refund = refundService.getByProcessInstanceId(processInstanceId); + + return success(BeanUtils.toBean(refund, BpmOARefundRespVO.class)); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundCreateReqVO.java new file mode 100644 index 00000000..0d583a3f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundCreateReqVO.java @@ -0,0 +1,58 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * 退款申请 创建 Request VO + * + * @author 符溶馨 + */ +@Schema(description = "管理后台 - 退款申请创建 Request VO") +@Data +@EqualsAndHashCode() +@ToString(callSuper = true) +public class BpmOARefundCreateReqVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "订单编号不能为空") + private String orderNo; + + @Schema(description = "归还物品明细", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @NotNull(message = "归还物品明细不能为空") + private List refundItems; + + @Schema(description = "扣款金额") + private BigDecimal chargebacksAmount; + + @Schema(description = "退款金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @NotNull(message = "退款金额不能为空") + private BigDecimal refundAmount; + + @Schema(description = "退款日期", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate refundDate; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String notes; + + @Schema(description = "流程实例编号") + private String processInstanceId; + + @Schema(description = "状态-参见 bpm_process_instance_result 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer result; + + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) + private List fileItems; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundItems.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundItems.java new file mode 100644 index 00000000..62675ecc --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundItems.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Schema(description = "管理后台 - 退款申请 归还物品明细 Request VO") +@Data +public class BpmOARefundItems { + + @Schema(description = "租赁物品类型") + private Integer rentalItemsType; + + @Schema(description = "归还数量") + private Integer number; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundRespVO.java new file mode 100644 index 00000000..ca4ea576 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOABaseRespVO; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * @author 符溶馨 + */ +@Schema(description = "管理后台 - 退款申请 请求Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmOARefundRespVO extends BpmOABaseRespVO { + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "订单编号不能为空") + private String orderNo; + + @Schema(description = "归还物品明细", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @NotNull(message = "归还物品明细不能为空") + private List refundItems; + + @Schema(description = "扣款金额") + private BigDecimal chargebacksAmount; + + @Schema(description = "退款金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @NotNull(message = "退款金额不能为空") + private BigDecimal refundAmount; + + @Schema(description = "退款日期", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate refundDate; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String notes; + + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) + private List fileItems; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java index f359ff51..8c36c5ea 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java @@ -1,10 +1,19 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund.BpmOARefundItems; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.*; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + /** * OA 转正申请 DO * @@ -33,6 +42,53 @@ public class BpmOARefundDO extends BaseDO { */ private Long userId; + /** + * 订单编号 + */ private String orderNo; + /** + * 归还物品明细 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List refundItems; + + /** + * 扣款金额 + */ + private BigDecimal chargebacksAmount; + + /** + * 退款金额 + */ + private BigDecimal refundAmount; + + /** + * 退款日期 + */ + private LocalDate refundDate; + + /** + * 备注 + */ + private String notes; + + /** + * 结果 + * 枚举 {@link BpmProcessInstanceResultEnum} + * 考虑到简单,所以直接复用了 BpmProcessInstanceResultEnum 枚举,也可以自己定义一个枚举哈 + */ + private Integer result; + + /** + * 对应的流程编号 + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + + /** + * 附件基本信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List fileItems ; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOARefundMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOARefundMapper.java new file mode 100644 index 00000000..9803f9dd --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOARefundMapper.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.oa; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOARefundDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BpmOARefundMapper extends BaseMapperX { +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundService.java new file mode 100644 index 00000000..9893d910 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundService.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund.BpmOARefundCreateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOARefundDO; + +import javax.validation.Valid; + +public interface BpmOARefundService { + + /** + * 创建转正申请 + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createRefund(Long userId, @Valid BpmOARefundCreateReqVO createReqVO); + + /** + * 更新转正申请的状态 + * + * @param id 编号 + * @param result 结果 + */ + void updateRefundResult(String processInstanceId, Long id, Integer result); + + /** + * 获得转正申请 + * + * @param id 编号 + * @return 转正申请 + */ + BpmOARefundDO getRefund(Long id); + + /** + * 获得指定的转正申请 + * @param processInstanceId 流程实例编号 + * @return 转正申请 + */ + BpmOARefundDO getByProcessInstanceId(String processInstanceId); +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java new file mode 100644 index 00000000..438863af --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund.BpmOARefundCreateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOARefundDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOARefundMapper; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_REFUND_CARD_NOT_EXISTS; + +/** + * OA 转正申请 Service 实现类 + * + * @author 符溶馨 + + */ +@Service +@Validated +public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARefundService{ + + /** + * OA 转正对应的流程定义 KEY + */ + public static final String PROCESS_KEY = "oa_refund_2"; + + @Resource + private BpmOARefundMapper refundMapper; + + @Resource + private BpmProcessInstanceApi processInstanceApi; + + @Resource + private BpmHistoryProcessInstanceService historyProcessInstanceService; + + @Resource + private BpmProcessInstanceService bpmProcessInstanceService; + + @Override + public Long createRefund(Long userId, BpmOARefundCreateReqVO createReqVO) { + + //插入OA 转正申请 + BpmOARefundDO refund = BeanUtils.toBean(createReqVO, BpmOARefundDO.class) + .setUserId(userId) + .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); + refundMapper.insert(refund) ; + + // 发起 BPM 流程 + Map processInstanceVariables = new HashMap<>(); + String processInstanceId = processInstanceApi.createProcessInstance(userId, + new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) + .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(refund.getId()))).getCheckedData(); + + // 将工作流的编号,更新到 OA 转正单中 + refundMapper.updateById(new BpmOARefundDO().setId(refund.getId()).setProcessInstanceId(processInstanceId)); + + // 判断是否为重新发起的流程 + if (createReqVO.getProcessInstanceId() != null && createReqVO.getResult() == 3) { + + historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId()); + } + + List fileItems = createReqVO.getFileItems() ; + //这里的逻辑,如果fileItems不为空,且有数据,那么说明是上传了附件的,则需要更工作流文件表对应的实例Id + if (fileItems != null && !fileItems.isEmpty()) { + uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ; + } + return refund.getId(); + } + + @Override + public void updateRefundResult(String processInstanceId, Long id, Integer result) { + + validateLeaveExists(id); + //审核通过 (最后节点) + if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) { + + ProcessInstance instance = bpmProcessInstanceService.getProcessInstance(processInstanceId); + + if (instance.isEnded()) { + + } + } + + refundMapper.updateById(new BpmOARefundDO().setId(id).setResult(result)); + } + + private void validateLeaveExists(Long id) { + if (refundMapper.selectById(id) == null) { + throw exception(OA_REFUND_CARD_NOT_EXISTS); + } + } + + @Override + public BpmOARefundDO getRefund(Long id) { + + return refundMapper.selectById(id); + } + + @Override + public BpmOARefundDO getByProcessInstanceId(String processInstanceId) { + + return refundMapper.selectOne(BpmOARefundDO::getProcessInstanceId, processInstanceId); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOARefundResultListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOARefundResultListener.java new file mode 100644 index 00000000..599fa002 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOARefundResultListener.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.service.oa.listener; + +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent; +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventListener; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOARefundService; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOARefundServiceImpl; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * OA 转正单的结果的监听器实现类 + * + * @author 符溶馨 + */ +@Component +public class BpmOARefundResultListener extends BpmProcessInstanceResultEventListener { + + @Resource + private BpmOARefundService refundService; + + @Override + protected String getProcessDefinitionKey() { + + return BpmOARefundServiceImpl.PROCESS_KEY; + } + + @Override + protected void onEvent(BpmProcessInstanceResultEvent event) { + refundService.updateRefundResult(event.getId(), Long.parseLong(event.getBusinessKey()), event.getResult()); + } +} From 357fa8aa13b1dca99000169347e7a8258dfd16d2 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sat, 23 Nov 2024 13:46:35 +0800 Subject: [PATCH 10/18] =?UTF-8?q?feat(bpm):=20=E6=B7=BB=E5=8A=A0=20OA=20?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=94=B3=E8=AF=B7=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 OA项目申请相关的数据结构和接口- 实现 OA 项目申请的创建、查询和结果更新功能- 添加 OA 项目申请的结果监听器 - 优化错误码命名,提高可读性 --- .../module/bpm/enums/ErrorCodeConstants.java | 3 +- .../admin/oa/BpmOAProjectController.java | 61 +++++++++ .../vo/project/BpmOAProjectCreateReqVO.java | 81 ++++++++++++ .../oa/vo/project/BpmOAProjectRespVO.java | 75 +++++++++++ .../bpm/dal/dataobject/oa/BpmOAProjectDO.java | 117 +++++++++++++++++ .../bpm/dal/dataobject/oa/BpmOARefundDO.java | 4 +- .../bpm/dal/mysql/oa/BpmOAProjectMapper.java | 9 ++ .../bpm/service/oa/BpmOAProjectService.java | 41 ++++++ .../service/oa/BpmOAProjectServiceImpl.java | 118 ++++++++++++++++++ .../service/oa/BpmOARefundServiceImpl.java | 10 +- .../listener/BpmOAProjectResultListener.java | 32 +++++ 11 files changed, 542 insertions(+), 9 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAProjectController.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectCreateReqVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectRespVO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAProjectDO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAProjectMapper.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectService.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectServiceImpl.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOAProjectResultListener.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java index ed08ccde..8775f08a 100644 --- a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/enums/ErrorCodeConstants.java @@ -57,7 +57,8 @@ public interface ErrorCodeConstants { ErrorCode OA_EVECTION_IS_EXISTS = new ErrorCode(1_009_001_120, "该时间段您正在出差!请重新选择正确出差时间。"); ErrorCode OA_INVOICE_NOT_EXISTS = new ErrorCode(1_009_001_121, "开票申请不存在"); ErrorCode OA_REPLACEMENT_CARD_NOT_EXISTS = new ErrorCode(1_009_001_122, "补卡申请不存在"); - ErrorCode OA_REFUND_CARD_NOT_EXISTS = new ErrorCode(1_009_001_123, "退款申请不存在"); + ErrorCode OA_REFUND_NOT_EXISTS = new ErrorCode(1_009_001_123, "退款申请不存在"); + ErrorCode OA_PROJECT_NOT_EXISTS = new ErrorCode(1_009_001_124, "项目申请不存在"); // ========== 流程模型 1-009-002-000 ========== diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAProjectController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAProjectController.java new file mode 100644 index 00000000..931461eb --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAProjectController.java @@ -0,0 +1,61 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.project.BpmOAProjectCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.project.BpmOAProjectRespVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProjectDO; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProjectService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import javax.validation.Valid; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; + +/** + * OA 项目申请 Controller + * + * @author 符溶馨 + */ +@Tag(name = "管理后台 - OA 项目申请") +@RestController +@RequestMapping("/bpm/oa/project") +@Validated +public class BpmOAProjectController { + + @Resource + private BpmOAProjectService projectService; + + @PostMapping("/create") + @Operation(summary = "创建请求申请") + public CommonResult createProject(@Valid @RequestBody BpmOAProjectCreateReqVO createReqVO) { + + return success(projectService.createProject(getLoginUserId(), createReqVO)); + } + + @GetMapping("/get") + @Operation(summary = "获得项目申请") + @Parameter(name = "id", description = "编号", required = true, example = "1024") + public CommonResult getProject(@RequestParam("id") Long id) { + + BpmOAProjectDO project = projectService.getProject(id); + + return success(BeanUtils.toBean(project, BpmOAProjectRespVO.class)); + } + + @GetMapping("/getByProcessInstanceId") + @Operation(summary = "获得项目申请") + @Parameter(name = "processInstanceId", description = "流程实例编号", required = true, example = "1024") + public CommonResult getByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) { + + BpmOAProjectDO project = projectService.getByProcessInstanceId(processInstanceId); + + return success(BeanUtils.toBean(project, BpmOAProjectRespVO.class)); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectCreateReqVO.java new file mode 100644 index 00000000..7a7e354a --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectCreateReqVO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.project; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * 项目申请 创建 Request VO + * + * @author 符溶馨 + */ +@Schema(description = "管理后台 - 项目申请创建 Request VO") +@Data +@EqualsAndHashCode() +@ToString(callSuper = true) +public class BpmOAProjectCreateReqVO { + + @Schema(description = "项目类型", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目类型不能为空") + private Integer type; + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目名称不能为空") + private String name; + + @Schema(description = "责任部门", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任部门不能为空") + private Long responsibleDept; + + @Schema(description = "参与部门集合") + private Set participationDept; + + @Schema(description = "责任人", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任人不能为空") + private Long directorUserId; + + @Schema(description = "项目开始日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目开始日期不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate startDate; + + @Schema(description = "项目结束日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目结束日期不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate endDate; + + @Schema(description = "是否长期项目", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private Integer isLongTerm; + + @Schema(description = "项目预算", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目预算不能为空") + private BigDecimal projectBudget; + + @Schema(description = "项目内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目内容不能为空") + private String content; + + @Schema(description = "项目额外属性", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private Map dynamicAttribute; + + @Schema(description = "流程实例编号") + private String processInstanceId; + + @Schema(description = "状态-参见 bpm_process_instance_result 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer result; + + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) + private List fileItems; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectRespVO.java new file mode 100644 index 00000000..439f779c --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectRespVO.java @@ -0,0 +1,75 @@ +package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.project; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.BpmOABaseRespVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund.BpmOARefundItems; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * @author 符溶馨 + */ +@Schema(description = "管理后台 - 项目申请 请求Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class BpmOAProjectRespVO extends BpmOABaseRespVO { + + @Schema(description = "项目类型", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目类型不能为空") + private Integer type; + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目名称不能为空") + private String name; + + @Schema(description = "责任部门", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任部门不能为空") + private Long responsibleDept; + + @Schema(description = "参与部门集合") + private Set participationDept; + + @Schema(description = "责任人", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任人不能为空") + private Long directorUserId; + + @Schema(description = "项目开始日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目开始日期不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate startDate; + + @Schema(description = "项目结束日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目结束日期不能为空") + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate endDate; + + @Schema(description = "是否长期项目", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private Integer isLongTerm; + + @Schema(description = "项目预算", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目预算不能为空") + private BigDecimal projectBudget; + + @Schema(description = "项目内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目内容不能为空") + private String content; + + @Schema(description = "项目额外属性", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private Map dynamicAttribute; + + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) + private List fileItems; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAProjectDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAProjectDO.java new file mode 100644 index 00000000..cbaec208 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAProjectDO.java @@ -0,0 +1,117 @@ +package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; +import lombok.*; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * OA 项目申请 DO + * + * @author 符溶馨 + */ +@TableName(value ="bpm_oa_refund", autoResultMap = true) +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class BpmOAProjectDO extends BaseDO { + + /** + * 出差表单主键 + */ + @TableId + private Long id; + + /** + * 申请人的用户编号 + * 关联 AdminUserDO 的 id 属性 + */ + private Long userId; + + /** + * 项目类型 + */ + private Integer type; + + /** + * 项目名称 + */ + private String name; + + /** + * 责任部门 + */ + private Long responsibleDept; + + /** + * 参与部门 + */ + private Set participationDept; + + /** + * 责任人 + */ + private Long directorUserId; + + /** + * 项目开始日期 + */ + private LocalDate startDate; + + /** + * 项目结束日期 + */ + private LocalDate endDate; + + /** + * 是否为长期项目 | 0否 1是 + */ + private Integer isLongTerm; + + /** + * 项目预算 + */ + private BigDecimal projectBudget; + + /** + * 项目内容 + */ + private String content; + + /** + * 项目额外属性 + */ + private Map dynamicAttribute; + + /** + * 结果 + * 枚举 {@link BpmProcessInstanceResultEnum} + * 考虑到简单,所以直接复用了 BpmProcessInstanceResultEnum 枚举,也可以自己定义一个枚举哈 + */ + private Integer result; + + /** + * 对应的流程编号 + * 关联 ProcessInstance 的 id 属性 + */ + private String processInstanceId; + + /** + * 附件基本信息 + */ + @TableField(typeHandler = JacksonTypeHandler.class) + private List fileItems; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java index 8c36c5ea..f0e4d2c9 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java @@ -15,11 +15,9 @@ import java.time.LocalDate; import java.util.List; /** - * OA 转正申请 DO - * + * OA 退款申请 DO * * @author 符溶馨 - */ @TableName(value ="bpm_oa_refund", autoResultMap = true) @Data diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAProjectMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAProjectMapper.java new file mode 100644 index 00000000..52ddf7ea --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAProjectMapper.java @@ -0,0 +1,9 @@ +package cn.iocoder.yudao.module.bpm.dal.mysql.oa; + +import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProjectDO; +import org.apache.ibatis.annotations.Mapper; + +@Mapper +public interface BpmOAProjectMapper extends BaseMapperX { +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectService.java new file mode 100644 index 00000000..d384d7ee --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectService.java @@ -0,0 +1,41 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.project.BpmOAProjectCreateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProjectDO; + +import javax.validation.Valid; + +public interface BpmOAProjectService { + + /** + * 创建转正申请 + * + * @param userId 用户编号 + * @param createReqVO 创建信息 + * @return 编号 + */ + Long createProject(Long userId, @Valid BpmOAProjectCreateReqVO createReqVO); + + /** + * 更新转正申请的状态 + * + * @param id 编号 + * @param result 结果 + */ + void updateProjectResult(String processInstanceId, Long id, Integer result); + + /** + * 获得转正申请 + * + * @param id 编号 + * @return 转正申请 + */ + BpmOAProjectDO getProject(Long id); + + /** + * 获得指定的转正申请 + * @param processInstanceId 流程实例编号 + * @return 转正申请 + */ + BpmOAProjectDO getByProcessInstanceId(String processInstanceId); +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectServiceImpl.java new file mode 100644 index 00000000..611bfbb2 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectServiceImpl.java @@ -0,0 +1,118 @@ +package cn.iocoder.yudao.module.bpm.service.oa; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; +import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.project.BpmOAProjectCreateReqVO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProjectDO; +import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAProjectMapper; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; +import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; +import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import org.flowable.engine.runtime.ProcessInstance; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import javax.annotation.Resource; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_PROJECT_NOT_EXISTS; + +/** + * OA 项目申请 Service 实现类 + * + * @author 符溶馨 + + */ +@Service +@Validated +public class BpmOAProjectServiceImpl extends BpmOABaseService implements BpmOAProjectService{ + + /** + * OA 项目申请对应的流程定义 KEY + */ + public static final String PROCESS_KEY = "oa_project_2"; + + @Resource + private BpmOAProjectMapper projectMapper; + + @Resource + private BpmProcessInstanceApi processInstanceApi; + + @Resource + private BpmHistoryProcessInstanceService historyProcessInstanceService; + + @Resource + private BpmProcessInstanceService bpmProcessInstanceService; + + @Override + public Long createProject(Long userId, BpmOAProjectCreateReqVO createReqVO) { + + //插入OA 项目申请 + BpmOAProjectDO project = BeanUtils.toBean(createReqVO, BpmOAProjectDO.class) + .setUserId(userId) + .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); + projectMapper.insert(project) ; + + // 发起 BPM 流程 + Map processInstanceVariables = new HashMap<>(); + String processInstanceId = processInstanceApi.createProcessInstance(userId, + new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) + .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(project.getId()))).getCheckedData(); + + // 将工作流的编号,更新到 OA 项目申请单中 + projectMapper.updateById(new BpmOAProjectDO().setId(project.getId()).setProcessInstanceId(processInstanceId)); + + // 判断是否为重新发起的流程 + if (createReqVO.getProcessInstanceId() != null && createReqVO.getResult() == 3) { + + historyProcessInstanceService.createHistoryProcessInstance(processInstanceId, createReqVO.getProcessInstanceId()); + } + + List fileItems = createReqVO.getFileItems() ; + //这里的逻辑,如果fileItems不为空,且有数据,那么说明是上传了附件的,则需要更工作流文件表对应的实例Id + if (fileItems != null && !fileItems.isEmpty()) { + uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ; + } + return project.getId(); + } + + @Override + public void updateProjectResult(String processInstanceId, Long id, Integer result) { + + validateLeaveExists(id); + //审核通过 (最后节点) + if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) { + + ProcessInstance instance = bpmProcessInstanceService.getProcessInstance(processInstanceId); + + if (instance.isEnded()) { + + } + } + + projectMapper.updateById(new BpmOAProjectDO().setId(id).setResult(result)); + } + + private void validateLeaveExists(Long id) { + if (projectMapper.selectById(id) == null) { + throw exception(OA_PROJECT_NOT_EXISTS); + } + } + + @Override + public BpmOAProjectDO getProject(Long id) { + + return projectMapper.selectById(id); + } + + @Override + public BpmOAProjectDO getByProcessInstanceId(String processInstanceId) { + + return projectMapper.selectOne(BpmOAProjectDO::getProcessInstanceId, processInstanceId); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java index 438863af..07e62c9b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java @@ -20,10 +20,10 @@ import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; -import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_REFUND_CARD_NOT_EXISTS; +import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_REFUND_NOT_EXISTS; /** - * OA 转正申请 Service 实现类 + * OA 退款申请 Service 实现类 * * @author 符溶馨 @@ -33,7 +33,7 @@ import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_REFUND_CAR public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARefundService{ /** - * OA 转正对应的流程定义 KEY + * OA 退款对应的流程定义 KEY */ public static final String PROCESS_KEY = "oa_refund_2"; @@ -52,7 +52,7 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef @Override public Long createRefund(Long userId, BpmOARefundCreateReqVO createReqVO) { - //插入OA 转正申请 + //插入OA 退款申请 BpmOARefundDO refund = BeanUtils.toBean(createReqVO, BpmOARefundDO.class) .setUserId(userId) .setResult(BpmProcessInstanceResultEnum.PROCESS.getResult()); @@ -100,7 +100,7 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef private void validateLeaveExists(Long id) { if (refundMapper.selectById(id) == null) { - throw exception(OA_REFUND_CARD_NOT_EXISTS); + throw exception(OA_REFUND_NOT_EXISTS); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOAProjectResultListener.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOAProjectResultListener.java new file mode 100644 index 00000000..c27188b3 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/listener/BpmOAProjectResultListener.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.bpm.service.oa.listener; + +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEvent; +import cn.iocoder.yudao.module.bpm.framework.bpm.core.event.BpmProcessInstanceResultEventListener; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProjectService; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProjectServiceImpl; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * OA 项目申请单的结果的监听器实现类 + * + * @author 符溶馨 + */ +@Component +public class BpmOAProjectResultListener extends BpmProcessInstanceResultEventListener { + + @Resource + private BpmOAProjectService projectService; + + @Override + protected String getProcessDefinitionKey() { + + return BpmOAProjectServiceImpl.PROCESS_KEY; + } + + @Override + protected void onEvent(BpmProcessInstanceResultEvent event) { + projectService.updateProjectResult(event.getId(), Long.parseLong(event.getBusinessKey()), event.getResult()); + } +} From 58929c52242210fc89e9839ee6e94d9dc2b6d9bb Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Sat, 23 Nov 2024 14:20:43 +0800 Subject: [PATCH 11/18] =?UTF-8?q?feat(bpm):=20=E6=96=B0=E5=A2=9E=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E7=AE=A1=E7=90=86=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 BpmOAProjectDO 类用于项目管理 -增加参与部门和项目额外属性字段 - 使用 JsonLongSetTypeHandler 和 JacksonTypeHandler 处理复杂数据类型 --- .../yudao/module/bpm/dal/dataobject/oa/BpmOAProjectDO.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAProjectDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAProjectDO.java index cbaec208..09546518 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAProjectDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOAProjectDO.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.bpm.dal.dataobject.oa; import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import cn.iocoder.yudao.framework.mybatis.core.type.JsonLongSetTypeHandler; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; @@ -20,7 +21,7 @@ import java.util.Set; * * @author 符溶馨 */ -@TableName(value ="bpm_oa_refund", autoResultMap = true) +@TableName(value ="bpm_oa_project", autoResultMap = true) @Data @EqualsAndHashCode(callSuper = true) @ToString(callSuper = true) @@ -59,6 +60,7 @@ public class BpmOAProjectDO extends BaseDO { /** * 参与部门 */ + @TableField(typeHandler = JsonLongSetTypeHandler.class) private Set participationDept; /** @@ -94,6 +96,7 @@ public class BpmOAProjectDO extends BaseDO { /** * 项目额外属性 */ + @TableField(typeHandler = JacksonTypeHandler.class) private Map dynamicAttribute; /** From ce26b95c08a54d0e104aa24458b0fc919e84afd5 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Mon, 25 Nov 2024 10:00:07 +0800 Subject: [PATCH 12/18] =?UTF-8?q?feat(bpm):=20=E6=95=B4=E5=90=88=E7=A7=9F?= =?UTF-8?q?=E8=B5=81=E8=AE=A2=E5=8D=95=E9=80=80=E6=AC=BE=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 RentalOrderApi 和 RentalDepositRecordApi接口 - 实现租赁订单状态更新和退款金额校验功能 - 添加租赁订单相关数据结构和接口实现 - 修改租赁订单状态枚举,增加等待退款中状态 --- .../rpc/config/RpcConfiguration.java | 5 +- .../service/oa/BpmOARefundServiceImpl.java | 46 ++++++++++++++-- .../api/rental/RentalDepositRecordApi.java | 29 ++++++++++ .../system/api/rental/RentalOrderApi.java | 25 +++++++++ .../rental/dto/RentalDepositRecordDTO.java | 53 +++++++++++++++++++ .../system/api/rental/dto/RentalOrderDTO.java | 37 +++++++++++++ .../rental/RentalDepositRecordApiImpl.java | 40 ++++++++++++++ .../system/api/rental/RentalOrderApiImpl.java | 27 ++++++++++ .../rental/vo/order/RentalOrderPageReqVO.java | 2 +- .../rental/vo/order/RentalOrderRespVO.java | 2 +- .../rental/vo/order/RentalOrderSaveReqVO.java | 2 +- .../dal/dataobject/rental/RentalOrderDO.java | 2 +- .../service/rental/RentalOrderService.java | 6 +++ .../rental/RentalOrderServiceImpl.java | 16 ++++++ 14 files changed, 283 insertions(+), 9 deletions(-) create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApi.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalDepositRecordDTO.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalOrderDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java index 56558f7f..30bcc46f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java @@ -16,6 +16,8 @@ import cn.iocoder.yudao.module.system.api.holiday.HolidayApi; import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; import cn.iocoder.yudao.module.system.api.permission.RoleApi; import cn.iocoder.yudao.module.system.api.position.PositionApi; +import cn.iocoder.yudao.module.system.api.rental.RentalDepositRecordApi; +import cn.iocoder.yudao.module.system.api.rental.RentalOrderApi; import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; import cn.iocoder.yudao.module.system.api.social.SocialClientApi; import cn.iocoder.yudao.module.system.api.subscribe.SubscribeMessageSendApi; @@ -28,7 +30,8 @@ import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @EnableFeignClients(clients = {FileApi.class, RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class, SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class, BankApi.class, ConfigApi.class, PositionApi.class, SupplierApi.class, AssetsApi.class, - AssetsTypeApi.class, AssetReceiveApi.class, AttendanceApi.class, AttendanceGroupApi.class, WorkOvertimeApi.class, HolidayApi.class + AssetsTypeApi.class, AssetReceiveApi.class, AttendanceApi.class, AttendanceGroupApi.class, WorkOvertimeApi.class, HolidayApi.class, + RentalOrderApi.class, RentalDepositRecordApi.class }) public class RpcConfiguration { } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java index 07e62c9b..b1533dc4 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java @@ -10,17 +10,22 @@ import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOARefundMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.system.api.rental.RentalDepositRecordApi; +import cn.iocoder.yudao.module.system.api.rental.RentalOrderApi; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalOrderDTO; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.math.BigDecimal; import java.util.HashMap; import java.util.List; import java.util.Map; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_REFUND_NOT_EXISTS; +import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.RENTAL_REFUND_AMOUNT_EXCESS; /** * OA 退款申请 Service 实现类 @@ -49,9 +54,18 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef @Resource private BpmProcessInstanceService bpmProcessInstanceService; + @Resource + private RentalOrderApi rentalOrderApi; + + @Resource + private RentalDepositRecordApi depositRecordApi; + @Override public Long createRefund(Long userId, BpmOARefundCreateReqVO createReqVO) { + // 发起流程前 校验扣款金额+退款金额是否等于已收金额 + validateRefundAmount(createReqVO.getOrderNo(), createReqVO.getChargebacksAmount(), createReqVO.getRefundAmount()); + //插入OA 退款申请 BpmOARefundDO refund = BeanUtils.toBean(createReqVO, BpmOARefundDO.class) .setUserId(userId) @@ -64,7 +78,7 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY) .setVariables(processInstanceVariables).setBusinessKey(String.valueOf(refund.getId()))).getCheckedData(); - // 将工作流的编号,更新到 OA 转正单中 + // 将工作流的编号,更新到 OA 退款申请单中 refundMapper.updateById(new BpmOARefundDO().setId(refund.getId()).setProcessInstanceId(processInstanceId)); // 判断是否为重新发起的流程 @@ -78,13 +92,30 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef if (fileItems != null && !fileItems.isEmpty()) { uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ; } + + // 退款申请发起后,变更租赁订单状态为 退款中 + rentalOrderApi.updateOrder(new RentalOrderDTO() + .setOrderNo(refund.getOrderNo()) + .setStatus(2)); + return refund.getId(); } + /** + * 校验扣款金额+退款金额是否等于已收金额 + */ + private void validateRefundAmount(String orderNo, BigDecimal chargebacksAmount, BigDecimal refundAmount) { + + BigDecimal recordAmount = depositRecordApi.getRecordAmount(orderNo).getCheckedData(); + if (recordAmount.compareTo(chargebacksAmount.add(refundAmount)) != 0) { + throw exception(RENTAL_REFUND_AMOUNT_EXCESS); + } + } + @Override public void updateRefundResult(String processInstanceId, Long id, Integer result) { - validateLeaveExists(id); + BpmOARefundDO refundDO = validateLeaveExists(id); //审核通过 (最后节点) if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) { @@ -92,16 +123,23 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef if (instance.isEnded()) { + // 审批通过后 更新租赁订单信息 + rentalOrderApi.updateOrder(new RentalOrderDTO() + .setOrderNo(refundDO.getOrderNo()) + .setChargebacksAmount(refundDO.getChargebacksAmount()) + .setStatus(3)); // 状态变更为 等待退款中 } } refundMapper.updateById(new BpmOARefundDO().setId(id).setResult(result)); } - private void validateLeaveExists(Long id) { - if (refundMapper.selectById(id) == null) { + private BpmOARefundDO validateLeaveExists(Long id) { + BpmOARefundDO refundDO = refundMapper.selectById(id); + if (refundDO == null) { throw exception(OA_REFUND_NOT_EXISTS); } + return refundDO; } @Override diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApi.java new file mode 100644 index 00000000..bcca9566 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApi.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.system.api.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalDepositRecordDTO; +import cn.iocoder.yudao.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import java.math.BigDecimal; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 租赁订单金额记录") +public interface RentalDepositRecordApi { + + String PREFIX = ApiConstants.PREFIX + "/rental-deposit"; + + @PutMapping(PREFIX + "/create") + @Operation(summary = "创建租赁订单出入张记录") + CommonResult create(@RequestBody RentalDepositRecordDTO createReqVO); + + @GetMapping(PREFIX + "/getRecordAmount") + @Operation(summary = "获取租赁订单已收取的金额") + CommonResult getRecordAmount(@RequestParam("orderNo") String orderNo); +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java new file mode 100644 index 00000000..1b6eaff9 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.api.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.system.api.position.dto.PositionDTO; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalOrderDTO; +import cn.iocoder.yudao.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 租赁订单") +public interface RentalOrderApi { + + String PREFIX = ApiConstants.PREFIX + "/rental-order"; + + @PutMapping(PREFIX + "/update") + @Operation(summary = "更新租赁订单信息") + CommonResult updateOrder(@RequestBody RentalOrderDTO updateReqVO); +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalDepositRecordDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalDepositRecordDTO.java new file mode 100644 index 00000000..2f71af03 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalDepositRecordDTO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.system.api.rental.dto; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +@Schema(description = "管理后台 - 租赁订单押金记录新增/修改 Request VO") +@Data +public class RentalDepositRecordDTO { + + @Schema(description = "租赁订单押金记录表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "订单编号不能为空") + private String orderNo; + + @Schema(description = "支付方式 | 1支付宝 2微信 3银行卡", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "支付方式不能为空") + private Integer paymentMethod; + + @Schema(description = "交易订单号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "交易订单号不能为空") + private String transactionOrderNumber; + + @Schema(description = "银行卡号") + private String bankNo; + + @Schema(description = "客户银行卡号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "客户银行卡号不能为空") + private String customerBankNo; + + @Schema(description = "收款/退款金额", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收款/退款金额不能为空") + private BigDecimal amount; + + @Schema(description = "收款/退款日期", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "收款/退款日期不能为空") + private LocalDate paymentDate; + + @Schema(description = "类型 | 1收款 2退款", example = "1") + private Integer type; + + @Schema(description = "附件信息") + private List fileItems; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalOrderDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalOrderDTO.java new file mode 100644 index 00000000..39847afc --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalOrderDTO.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.system.api.rental.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotNull; +import java.math.BigDecimal; + +@Schema(description = "管理后台 - 租赁订单新增/修改 Request VO") +@Data +public class RentalOrderDTO { + + @Schema(description = "租赁订单表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "订单编号") + private String orderNo; + + @Schema(description = "客户编号", requiredMode = Schema.RequiredMode.REQUIRED) + private Long customerId; + + @Schema(description = "收款人") + private String recipient; + + @Schema(description = "押金金额", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "押金金额不能为空") + private BigDecimal depositAmount; + + @Schema(description = "扣款金额") + private BigDecimal chargebacksAmount; + + @Schema(description = "备注") + private String notes; + + @Schema(description = "状态 | 1租赁中 2退款中 3已退") + private Integer status; +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java new file mode 100644 index 00000000..d54d80ce --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java @@ -0,0 +1,40 @@ +package cn.iocoder.yudao.module.system.api.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalDepositRecordDTO; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalOrderDTO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import cn.iocoder.yudao.module.system.service.rental.RentalDepositRecordService; +import cn.iocoder.yudao.module.system.service.rental.RentalOrderService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import java.math.BigDecimal; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class RentalDepositRecordApiImpl implements RentalDepositRecordApi { + + @Resource + private RentalDepositRecordService rentalDepositRecordService; + + @Override + public CommonResult create(RentalDepositRecordDTO createReqVO) { + RentalDepositRecordSaveReqVO depositRecord = BeanUtils.toBean(createReqVO, RentalDepositRecordSaveReqVO.class); + return success(rentalDepositRecordService.createRentalDepositRecord(depositRecord)); + } + + @Override + public CommonResult getRecordAmount(String orderNo) { + RentalDepositAmountReqVO reqVO = rentalDepositRecordService.getRentalDepositRecordAmount(orderNo, false); + return success(reqVO.getReceivedAmount()); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java new file mode 100644 index 00000000..4615f26e --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.system.api.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalOrderDTO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; +import cn.iocoder.yudao.module.system.service.rental.RentalOrderService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class RentalOrderApiImpl implements RentalOrderApi { + + @Resource + private RentalOrderService rentalOrderService; + + @Override + public CommonResult updateOrder(RentalOrderDTO updateReqVO) { + rentalOrderService.update(BeanUtils.toBean(updateReqVO, RentalOrderSaveReqVO.class)); + return success(true); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java index b5346fe7..d1880eaf 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderPageReqVO.java @@ -29,7 +29,7 @@ public class RentalOrderPageReqVO extends PageParam { @Schema(description = "押金金额") private Integer depositAmount; - @Schema(description = "状态 | 1租赁中 2退款中 3已退") + @Schema(description = "状态 | 1租赁中 2退款申请中 3等待退款中 4已退款") private Integer status; @Schema(description = "创建时间") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java index b4baa774..c0e54065 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java @@ -46,7 +46,7 @@ public class RentalOrderRespVO { @Schema(description = "备注") private String notes; - @Schema(description = "状态 | 1租赁中 2退款中 3已退") + @Schema(description = "状态 | 1租赁中 2退款申请中 3等待退款中 4已退款") private Integer status; @Schema(description = "创建时间") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java index 93de6f0d..6ca771f1 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderSaveReqVO.java @@ -37,7 +37,7 @@ public class RentalOrderSaveReqVO { @Schema(description = "备注") private String notes; - @Schema(description = "状态 | 1租赁中 2退款中 3已退") + @Schema(description = "状态 | 1租赁中 2退款申请中 3等待退款中 4已退款") private Integer status; @Schema(description = "租赁物品记录") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java index 08d415ae..a19d4f68 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java @@ -53,7 +53,7 @@ public class RentalOrderDO extends BaseDO { */ private String notes; /** - * 状态 | 1租赁中 2退款中 3已退 + * 状态 | 1租赁中 2退款申请中 3等待退款中 4已退款 */ private Integer status; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java index c42cec47..62ee124e 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java @@ -31,6 +31,12 @@ public interface RentalOrderService { */ BigDecimal updateRentalOrder(@Valid RentalOrderSaveReqVO updateReqVO); + /** + * 更新租赁订单 + * @param updateReqVO 更新信息 + */ + void update(RentalOrderSaveReqVO updateReqVO); + /** * 删除租赁订单 * diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java index 221fc2ab..c5fba014 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java @@ -3,12 +3,15 @@ package cn.iocoder.yudao.module.system.service.rental; import cn.hutool.core.collection.CollectionUtil; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalOrderMapper; import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; @@ -115,6 +118,19 @@ public class RentalOrderServiceImpl implements RentalOrderService { return updateObj.getDepositAmount().subtract(updateObj.getChargebacksAmount() == null ? BigDecimal.ZERO : updateObj.getChargebacksAmount()); } + @Override + public void update(RentalOrderSaveReqVO updateReqVO) { + Long count = rentalOrderMapper.selectCount(RentalOrderDO::getOrderNo, updateReqVO.getOrderNo()); + if (count <= 0L) { + throw exception(RENTAL_ORDER_NOT_EXISTS); + } + + // 更新 + RentalOrderDO updateObj = BeanUtils.toBean(updateReqVO, RentalOrderDO.class); + rentalOrderMapper.update(updateObj, new LambdaQueryWrapperX() + .eq(RentalOrderDO::getOrderNo, updateReqVO.getOrderNo())); + } + @Override public void deleteRentalOrder(Long id) { // 校验存在 From f2641b4762ee590ccb212e31b7edfc76306c76e7 Mon Sep 17 00:00:00 2001 From: aikai Date: Mon, 25 Nov 2024 11:02:01 +0800 Subject: [PATCH 13/18] =?UTF-8?q?=E8=AF=B7=E5=81=87=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E4=B8=8A=E7=90=86=E7=94=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java index 11eb7d66..c0d7b149 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOALeaveServiceImpl.java @@ -134,7 +134,8 @@ public class BpmOALeaveServiceImpl extends BpmOABaseService implements BpmOALeav beginTimeStr = "1".equals(leave.getStartTimeExtraFields()) ? "上午" : "下午"; endTimeStr = "2".equals(leave.getStartTimeExtraFields()) ? "上午" : "下午"; } - String reason = "开始时间:" + leave.getStartTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY)) + " " + beginTimeStr + + String reason = createReqVO.getReason() + + " 开始时间:" + leave.getStartTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY)) + " " + beginTimeStr + " 结束时间:" + leave.getEndTime().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY)) + " " + endTimeStr; holidayApi.createUserHoliday(new CreateUserHolidayDTO().setUserId(leave.getUserId()).setHolidaySettingId(leave.getHolidaySettingId()) .setDirection(1).setHolidayBalance(duration).setReason(reason)); From de4568636167353ac9bab5cc71875157fc60e076 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Mon, 25 Nov 2024 23:22:06 +0800 Subject: [PATCH 14/18] =?UTF-8?q?feat(system):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=83=A8=E9=97=A8=E7=B1=BB=E5=9E=8B=E6=9E=9A=E4=B8=BE=E5=92=8C?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E7=AE=A1=E7=90=86=E7=9B=B8=E5=85=B3=E5=8A=9F?= =?UTF-8?q?=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增全局部门类型枚举 DeptTypeEnum - 在 DeptRespDTO 中添加部门类型字段 - 新增 ProjectApi 接口和 ProjectDTO 类,用于项目管理功能 --- .../framework/common/enums/DeptTypeEnum.java | 32 ++++++++ .../admin/oa/BpmOAProjectController.java | 77 ++++++++++++++++++- .../vo/project/BpmOAProjectCreateReqVO.java | 1 - .../oa/vo/project/BpmOAProjectRespVO.java | 16 ++-- .../admin/oa/vo/refund/BpmOARefundItems.java | 2 +- .../bpm/dal/mysql/oa/BpmOAProcureMapper.java | 5 ++ .../rpc/config/RpcConfiguration.java | 3 +- .../oa/BpmOAProcurePayServiceImpl.java | 41 +++++++--- .../service/oa/BpmOAProjectServiceImpl.java | 15 +++- .../service/oa/BpmOARefundServiceImpl.java | 14 +++- .../mapper/oa/BpmOAProcureMapper.xml | 21 +++++ .../system/api/dept/dto/DeptRespDTO.java | 3 + .../module/system/api/project/ProjectApi.java | 25 ++++++ .../system/api/project/dto/ProjectDTO.java | 69 +++++++++++++++++ .../system/api/project/ProjectApiImpl.java | 26 +++++++ .../admin/dept/vo/dept/DeptRespVO.java | 4 +- .../admin/dept/vo/dept/DeptSaveReqVO.java | 4 +- .../admin/project/ProjectController.java | 8 +- .../rental/RentalItemsRecordController.java | 10 +++ .../system/dal/dataobject/dept/DeptDO.java | 4 +- .../system/dal/mysql/dept/DeptMapper.java | 4 + .../mysql/rental/RentalItemsRecordMapper.java | 3 +- .../system/service/dept/DeptServiceImpl.java | 7 +- .../rental/RentalItemsRecordService.java | 2 +- .../rental/RentalItemsRecordServiceImpl.java | 8 +- .../main/resources/mapper/dept/DeptMapper.xml | 22 ++++++ .../mapper/rental/RentalItemsRecordMapper.xml | 4 +- 27 files changed, 387 insertions(+), 43 deletions(-) create mode 100644 yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DeptTypeEnum.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApi.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/dto/ProjectDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApiImpl.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/dept/DeptMapper.xml diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DeptTypeEnum.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DeptTypeEnum.java new file mode 100644 index 00000000..753944f3 --- /dev/null +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/enums/DeptTypeEnum.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.framework.common.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 全局部门类型枚举 + */ +@AllArgsConstructor +@Getter +public enum DeptTypeEnum { + + COMPANY("COMPANY", "公司"), + SALE_DEPT("SALE_DEPT", "销售部门"), + DEVELOPMENT_DEPT("DEVELOPMENT_DEPT", "开发部门"), + PRODUCTION_DEPT("TECHNICAL_DEPT", "生产部门"), + MARKETING_DEPT("MARKETING_DEPT", "市场部门"), + FINANCE_DEPT("FINANCE_DEPT", "财务部门"), + HR_DEPT("HR_DEPT", "人力部门"), + PURCHASING_DEPT("PURCHASING_DEPT", "采购部门"), + OTHER("OTHER", "其他部门"); + + /** + * 类型 + */ + private final String value; + + /** + * 名称 + */ + private final String name; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAProjectController.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAProjectController.java index 931461eb..a82f7744 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAProjectController.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/BpmOAProjectController.java @@ -6,6 +6,10 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.project.BpmOAProjectCr import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.project.BpmOAProjectRespVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProjectDO; import cn.iocoder.yudao.module.bpm.service.oa.BpmOAProjectService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; +import cn.iocoder.yudao.module.system.api.user.AdminUserApi; +import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; @@ -15,7 +19,14 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; /** @@ -32,6 +43,12 @@ public class BpmOAProjectController { @Resource private BpmOAProjectService projectService; + @Resource + private AdminUserApi userApi; + + @Resource + private DeptApi deptApi; + @PostMapping("/create") @Operation(summary = "创建请求申请") public CommonResult createProject(@Valid @RequestBody BpmOAProjectCreateReqVO createReqVO) { @@ -45,8 +62,36 @@ public class BpmOAProjectController { public CommonResult getProject(@RequestParam("id") Long id) { BpmOAProjectDO project = projectService.getProject(id); + BpmOAProjectRespVO respVO = BeanUtils.toBean(project, BpmOAProjectRespVO.class); - return success(BeanUtils.toBean(project, BpmOAProjectRespVO.class)); + if (respVO != null) { + + // 获取项目中所有部门编号列表 + Set deptIds = respVO.getParticipationDept() == null ? new HashSet<>() : respVO.getParticipationDept(); + deptIds.add(respVO.getResponsibleDept()); + + // 获取所有用户信息 + AdminUserRespDTO userRespDTO = userApi.getUser(respVO.getDirectorUserId()).getCheckedData(); + // 获取所有部门信息 + List deptDOS = deptApi.getDeptList(deptIds).getCheckedData(); + Map deptMap = convertMap(deptDOS, DeptRespDTO::getId); + + // 设置责任人名称 + respVO.setDirectorUserName(userRespDTO.getNickname()); + + // 筛选出不是责任人部门的部门信息 + List deptVOs = deptDOS.stream() + .filter(dept -> !dept.getId().equals(respVO.getResponsibleDept())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任部门名称 + respVO.setResponsibleDeptName(deptMap.get(respVO.getResponsibleDept()).getName()); + // 拼接参与部门名称 + respVO.setParticipationDeptName(deptVOs.stream().map(DeptRespDTO::getName).collect(Collectors.joining("、"))); + } + + return success(respVO); } @GetMapping("/getByProcessInstanceId") @@ -55,7 +100,35 @@ public class BpmOAProjectController { public CommonResult getByProcessInstanceId(@RequestParam("processInstanceId") String processInstanceId) { BpmOAProjectDO project = projectService.getByProcessInstanceId(processInstanceId); + BpmOAProjectRespVO respVO = BeanUtils.toBean(project, BpmOAProjectRespVO.class); - return success(BeanUtils.toBean(project, BpmOAProjectRespVO.class)); + if (respVO != null) { + + // 获取项目中所有部门编号列表 + Set deptIds = respVO.getParticipationDept() == null ? new HashSet<>() : respVO.getParticipationDept(); + deptIds.add(respVO.getResponsibleDept()); + + // 获取所有用户信息 + AdminUserRespDTO userRespDTO = userApi.getUser(respVO.getDirectorUserId()).getCheckedData(); + // 获取所有部门信息 + List deptDOS = deptApi.getDeptList(deptIds).getCheckedData(); + Map deptMap = convertMap(deptDOS, DeptRespDTO::getId); + + // 设置责任人名称 + respVO.setDirectorUserName(userRespDTO.getNickname()); + + // 筛选出不是责任人部门的部门信息 + List deptVOs = deptDOS.stream() + .filter(dept -> !dept.getId().equals(respVO.getResponsibleDept())) + .distinct() + .collect(Collectors.toList()); + + // 设置责任部门名称 + respVO.setResponsibleDeptName(deptMap.get(respVO.getResponsibleDept()).getName()); + // 拼接参与部门名称 + respVO.setParticipationDeptName(deptVOs.stream().map(DeptRespDTO::getName).collect(Collectors.joining("、"))); + } + + return success(respVO); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectCreateReqVO.java index 7a7e354a..d8fcfdc0 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectCreateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectCreateReqVO.java @@ -52,7 +52,6 @@ public class BpmOAProjectCreateReqVO { private LocalDate startDate; @Schema(description = "项目结束日期", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "项目结束日期不能为空") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) private LocalDate endDate; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectRespVO.java index 439f779c..7579630c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/project/BpmOAProjectRespVO.java @@ -28,31 +28,34 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_ public class BpmOAProjectRespVO extends BpmOABaseRespVO { @Schema(description = "项目类型", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "项目类型不能为空") private Integer type; @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "项目名称不能为空") private String name; @Schema(description = "责任部门", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "责任部门不能为空") private Long responsibleDept; + @Schema(description = "责任部门名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String responsibleDeptName; + @Schema(description = "参与部门集合") private Set participationDept; + @Schema(description = "参与部门名称集合") + private String participationDeptName; + @Schema(description = "责任人", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "责任人不能为空") private Long directorUserId; + @Schema(description = "责任人名称", requiredMode = Schema.RequiredMode.REQUIRED) + private String directorUserName; + @Schema(description = "项目开始日期", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "项目开始日期不能为空") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) private LocalDate startDate; @Schema(description = "项目结束日期", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "项目结束日期不能为空") @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) private LocalDate endDate; @@ -60,7 +63,6 @@ public class BpmOAProjectRespVO extends BpmOABaseRespVO { private Integer isLongTerm; @Schema(description = "项目预算", requiredMode = Schema.RequiredMode.REQUIRED) - @NotNull(message = "项目预算不能为空") private BigDecimal projectBudget; @Schema(description = "项目内容", requiredMode = Schema.RequiredMode.REQUIRED) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundItems.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundItems.java index 62675ecc..8d21eb38 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundItems.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundItems.java @@ -11,5 +11,5 @@ public class BpmOARefundItems { private Integer rentalItemsType; @Schema(description = "归还数量") - private Integer number; + private Integer rentalNumber; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAProcureMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAProcureMapper.java index 6ceb7eed..6f896f90 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAProcureMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAProcureMapper.java @@ -3,9 +3,13 @@ package cn.iocoder.yudao.module.bpm.dal.mysql.oa; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; +import cn.iocoder.yudao.framework.mybatis.core.query.MPJLambdaWrapperX; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.procure.BpmOAProcurePageReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAProcureDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; /** * OA 采购申请 Mapper @@ -30,4 +34,5 @@ public interface BpmOAProcureMapper extends BaseMapperX { .orderByDesc(BpmOAProcureDO::getId)); } + List selectListByDeptId(@Param("companyDeptId") Long companyDeptId); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java index 30bcc46f..dbab845c 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java @@ -16,6 +16,7 @@ import cn.iocoder.yudao.module.system.api.holiday.HolidayApi; import cn.iocoder.yudao.module.system.api.notify.NotifyMessageSendApi; import cn.iocoder.yudao.module.system.api.permission.RoleApi; import cn.iocoder.yudao.module.system.api.position.PositionApi; +import cn.iocoder.yudao.module.system.api.project.ProjectApi; import cn.iocoder.yudao.module.system.api.rental.RentalDepositRecordApi; import cn.iocoder.yudao.module.system.api.rental.RentalOrderApi; import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; @@ -31,7 +32,7 @@ import org.springframework.context.annotation.Configuration; @EnableFeignClients(clients = {FileApi.class, RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class, SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class, BankApi.class, ConfigApi.class, PositionApi.class, SupplierApi.class, AssetsApi.class, AssetsTypeApi.class, AssetReceiveApi.class, AttendanceApi.class, AttendanceGroupApi.class, WorkOvertimeApi.class, HolidayApi.class, - RentalOrderApi.class, RentalDepositRecordApi.class + RentalOrderApi.class, RentalDepositRecordApi.class, ProjectApi.class }) public class RpcConfiguration { } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProcurePayServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProcurePayServiceImpl.java index a4b60282..b27c2617 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProcurePayServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProcurePayServiceImpl.java @@ -1,5 +1,6 @@ package cn.iocoder.yudao.module.bpm.service.oa; +import cn.iocoder.yudao.framework.common.enums.DeptTypeEnum; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; @@ -28,6 +29,8 @@ import cn.iocoder.yudao.module.bpm.service.definition.BpmModelService; import cn.iocoder.yudao.module.bpm.service.financialpayment.FinancialPaymentService; import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.system.api.dept.DeptApi; +import cn.iocoder.yudao.module.system.api.dept.dto.DeptRespDTO; 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.query.LambdaQueryWrapper; @@ -38,6 +41,7 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -77,6 +81,9 @@ public class BpmOAProcurePayServiceImpl extends BpmOABaseService implements BpmO @Resource private AdminUserApi userApi; + @Resource + private DeptApi deptApi; + @Resource private BpmHistoryProcessInstanceService historyProcessInstanceService; @@ -154,15 +161,31 @@ public class BpmOAProcurePayServiceImpl extends BpmOABaseService implements BpmO public List getAvailablePurchaseOrders() { //获取当前登录用户id Long userId = WebFrameworkUtils.getLoginUserId(); - //查询当前登录用户所在部门所有用户id - CommonResult> userIdsResult = adminUserApi.getUserIdsByUserIdGroupByDept(userId); - List userIds = userIdsResult.getData(); - //根据用户ids 获取所有可用采购单 - return oaProcureMapper.selectList(new LambdaQueryWrapperX() - .in(BpmOAProcureDO::getUserId, userIds) - .eq(BpmOAProcureDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()) - .eq(BpmOAProcureDO::getPayFlag, BpmOAProcureDO.FLAG_FALSE) - ); + // 获取当前登录用的部门信息 + DeptRespDTO dto = deptApi.getDept(adminUserApi.getUser(userId).getCheckedData().getDeptId()).getCheckedData(); + + // 用户属于采购部时 + if (dto.getType().equals(DeptTypeEnum.PURCHASING_DEPT.getValue())) { + + // 获取用户所在公司信息 + DeptRespDTO company = deptApi.getUserCompanyDept(userId).getCheckedData(); + + // 查询当前用户所在公司下,所有部门可用的采购单 + return oaProcureMapper.selectListByDeptId(company.getId()); + + }else { + + //查询当前登录用户所在部门下所有用户的信息 + CommonResult> userIdsResult = adminUserApi.getUserIdsByUserIdGroupByDept(userId); + List userIds; userIds = userIdsResult.getData(); + + //根据用户ids 获取所有可用采购单 + return oaProcureMapper.selectList(new LambdaQueryWrapperX() + .in(BpmOAProcureDO::getUserId, userIds) + .eq(BpmOAProcureDO::getResult, BpmProcessInstanceResultEnum.APPROVE.getResult()) + .eq(BpmOAProcureDO::getPayFlag, BpmOAProcureDO.FLAG_FALSE) + ); + } } @Override diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectServiceImpl.java index 611bfbb2..2344633b 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOAProjectServiceImpl.java @@ -10,6 +10,8 @@ import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAProjectMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; +import cn.iocoder.yudao.module.system.api.project.ProjectApi; +import cn.iocoder.yudao.module.system.api.project.dto.ProjectDTO; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -49,6 +51,9 @@ public class BpmOAProjectServiceImpl extends BpmOABaseService implements BpmOAPr @Resource private BpmProcessInstanceService bpmProcessInstanceService; + @Resource + private ProjectApi projectApi; + @Override public Long createProject(Long userId, BpmOAProjectCreateReqVO createReqVO) { @@ -84,7 +89,7 @@ public class BpmOAProjectServiceImpl extends BpmOABaseService implements BpmOAPr @Override public void updateProjectResult(String processInstanceId, Long id, Integer result) { - validateLeaveExists(id); + BpmOAProjectDO project = validateLeaveExists(id); //审核通过 (最后节点) if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) { @@ -92,16 +97,20 @@ public class BpmOAProjectServiceImpl extends BpmOABaseService implements BpmOAPr if (instance.isEnded()) { + // 同步创建 项目 + projectApi.create(BeanUtils.toBean(project, ProjectDTO.class).setStatus(1)); } } projectMapper.updateById(new BpmOAProjectDO().setId(id).setResult(result)); } - private void validateLeaveExists(Long id) { - if (projectMapper.selectById(id) == null) { + private BpmOAProjectDO validateLeaveExists(Long id) { + BpmOAProjectDO project = projectMapper.selectById(id); + if (project == null) { throw exception(OA_PROJECT_NOT_EXISTS); } + return project; } @Override diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java index b1533dc4..dea81fff 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java @@ -93,7 +93,7 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ; } - // 退款申请发起后,变更租赁订单状态为 退款中 + // 退款申请发起后,变更租赁订单状态为 退款申请中 rentalOrderApi.updateOrder(new RentalOrderDTO() .setOrderNo(refund.getOrderNo()) .setStatus(2)); @@ -131,6 +131,18 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef } } + // -- 自己取消 + // -- 审核拒绝 + if (BpmProcessInstanceResultEnum.REJECT.getResult().equals(result) + || BpmProcessInstanceResultEnum.CANCEL.getResult().equals(result) + || BpmProcessInstanceResultEnum.BACK.getResult().equals(result)) { + + // 变更租赁订单状态 为租借中 + rentalOrderApi.updateOrder(new RentalOrderDTO() + .setOrderNo(refundDO.getOrderNo()) + .setStatus(1)); + } + refundMapper.updateById(new BpmOARefundDO().setId(id).setResult(result)); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/oa/BpmOAProcureMapper.xml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/oa/BpmOAProcureMapper.xml index b68bf6e0..037682b1 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/oa/BpmOAProcureMapper.xml +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/oa/BpmOAProcureMapper.xml @@ -9,4 +9,25 @@ 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/ --> + diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java index 6efff426..4e068487 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/dept/dto/DeptRespDTO.java @@ -19,6 +19,9 @@ public class DeptRespDTO { @Schema(description = "父部门编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Long parentId; + @Schema(description = "部门类型") + private String type; + @Schema(description = "部门层级", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") private Integer level; diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApi.java new file mode 100644 index 00000000..ab99f57c --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApi.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.system.api.project; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.system.api.position.dto.PositionDTO; +import cn.iocoder.yudao.module.system.api.project.dto.ProjectDTO; +import cn.iocoder.yudao.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 项目") +public interface ProjectApi { + + String PREFIX = ApiConstants.PREFIX + "/project"; + + @PostMapping(PREFIX + "/create") + @Operation(summary = "创建项目") + CommonResult create(@RequestBody ProjectDTO createReqVO); +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/dto/ProjectDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/dto/ProjectDTO.java new file mode 100644 index 00000000..f312351c --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/project/dto/ProjectDTO.java @@ -0,0 +1,69 @@ +package cn.iocoder.yudao.module.system.api.project.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import java.time.LocalDate; +import java.util.Map; +import java.util.Set; + +@Schema(description = "管理后台 - 项目管理新增/修改 Request VO") +@Data +public class ProjectDTO { + + @Schema(description = "项目管理表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Long id; + + @Schema(description = "项目编号") + private String projectNo; + + @Schema(description = "项目类型 | 字典值参考system_project_type", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "项目类型 | 字典值参考system_project_type不能为空") + private Integer type; + + @Schema(description = "项目名称", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "项目名称不能为空") + private String name; + + @Schema(description = "责任部门", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任部门不能为空") + private Long responsibleDept; + + @Schema(description = "参与部门集合", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "参与部门集合不能为空") + private Set participationDept; + + @Schema(description = "责任人用户编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "责任人用户编号不能为空") + private Long directorUserId; + + @Schema(description = "项目开始时间", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "项目开始时间不能为空") + private LocalDate startDate; + + @Schema(description = "项目结束时间") + private LocalDate endDate; + + @Schema(description = "是否长期 | 0否 1是") + private Integer isLongTerm; + + @Schema(description = "项目预算") + private Integer projectBudget; + + @Schema(description = "项目内容", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "项目内容不能为空") + private String content; + + @Schema(description = "项目人员用户编号集合") + private Set staff; + + @Schema(description = "项目额外属性") + private Map dynamicAttribute; + + @Schema(description = "项目状态 | 1 进行中 2已完成", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "项目状态 | 1 进行中 2已完成不能为空") + private Integer status; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApiImpl.java new file mode 100644 index 00000000..ba9a7202 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/project/ProjectApiImpl.java @@ -0,0 +1,26 @@ +package cn.iocoder.yudao.module.system.api.project; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.project.dto.ProjectDTO; +import cn.iocoder.yudao.module.system.controller.admin.project.vo.ProjectSaveReqVO; +import cn.iocoder.yudao.module.system.service.project.ProjectService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class ProjectApiImpl implements ProjectApi { + + @Resource + private ProjectService projectService; + + @Override + public CommonResult create(ProjectDTO createReqVO) { + return success(projectService.createProject(BeanUtils.toBean(createReqVO, ProjectSaveReqVO.class))); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java index c34ffb46..8ddeaa2d 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptRespVO.java @@ -21,8 +21,8 @@ public class DeptRespVO { @Schema(description = "父部门 ID", example = "1024") private Long parentId; - @Schema(description = "机构类型 | 0公司 1部门", example = "0") - private Integer type; + @Schema(description = "机构类型 | 字典值参考 system_dept_type", example = "0") + private String type; @Schema(description = "显示顺序不能为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") private Integer sort; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java index d3128323..c30e5b55 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/dept/vo/dept/DeptSaveReqVO.java @@ -28,8 +28,8 @@ public class DeptSaveReqVO { @Schema(description = "父部门 ID", example = "1024") private Long parentId; - @Schema(description = "机构类型 | 0公司 1部门", example = "0") - private Integer type; + @Schema(description = "机构类型 | 字典值参考 system_dept_type", example = "0") + private String type; @Schema(description = "显示顺序不能为空", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") @NotNull(message = "显示顺序不能为空") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java index c77d1c73..66299591 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/project/ProjectController.java @@ -157,7 +157,13 @@ public class ProjectController { // 设置责任人名称 item.setDirectorUserName(userMap.get(item.getDirectorUserId()).getNickname()); // 拼接项目人员名称 - item.setStaffName(userVOs.stream().map(AdminUserDO::getNickname).collect(Collectors.joining("、"))); + if (item.getStaff() != null) { + item.setStaffName(userVOs.stream() + .filter(user -> item.getStaff().contains(user.getId())) + .map(AdminUserDO::getNickname) + .collect(Collectors.joining("、"))); + + } // 筛选出不是责任人部门的部门信息 List deptVOs = deptDOS.stream() diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java index 3183f197..05757436 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalItemsRecordController.java @@ -6,6 +6,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerRespVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.customer.RentalCustomerSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsCountReqVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordRespVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; @@ -66,6 +67,15 @@ public class RentalItemsRecordController { return success(BeanUtils.toBean(rentalItemsRecordService.getRentalItemsRecord(id), RentalItemsRecordRespVO.class)); } + @GetMapping("/get-count") + @Operation(summary = "获取指定订单剩余租赁物品数量") + @Parameter(name = "orderNo", description = "订单编号", required = true) + @PreAuthorize("@ss.hasPermission('system:rental-items:query')") + public CommonResult> getRentalItemsRecord(@RequestParam("orderNo") String orderNo) { + + return success(rentalItemsRecordService.getRentalItemsCount(orderNo, false)); + } + @GetMapping("/page") @Operation(summary = "获得租赁物品记录分页") @PreAuthorize("@ss.hasPermission('system:rental-items:query')") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java index 46b1d0a7..f2699b9b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/dept/DeptDO.java @@ -42,9 +42,9 @@ public class DeptDO extends TenantBaseDO { */ private Long parentId; /** - * 机构类型 | 0公司 1部门 + * 机构类型 | 字典值参考 system_dept_type */ - private Integer type; + private String type; /** * 部门层级 */ diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java index 8d57329e..595ed075 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/dept/DeptMapper.java @@ -8,6 +8,7 @@ import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqV import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.Collection; import java.util.List; @@ -60,4 +61,7 @@ public interface DeptMapper extends BaseMapperX { return selectJoinOne(DeptDO.class, query); } + + List selectCompany(@Param("flag") String flag, + @Param("type") String type); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java index 76356d45..70ef1bd6 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/mysql/rental/RentalItemsRecordMapper.java @@ -25,5 +25,6 @@ public interface RentalItemsRecordMapper extends BaseMapperX selectRentalItemsCount(@Param("orderNo") String orderNo); + List selectRentalItemsCount(@Param("orderNo") String orderNo, + @Param("isUpdate") Boolean isUpdate); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java index 431da758..34ab8caa 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/dept/DeptServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ObjectUtil; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.common.enums.DeptTypeEnum; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; @@ -325,7 +326,7 @@ public class DeptServiceImpl implements DeptService { public List getCompanyDept() { return deptMapper.selectList(new LambdaQueryWrapperX() - .eq(DeptDO::getType, 0) + .eq(DeptDO::getType, DeptTypeEnum.COMPANY.getValue()) .eq(DeptDO::getVirtuallyStatus, 0) .eq(DeptDO::getStatus, CommonStatusEnum.ENABLE.getStatus())); } @@ -361,9 +362,7 @@ public class DeptServiceImpl implements DeptService { } // 根据所在部门信息获取 所在公司信息 - List companyDeptList = deptMapper.selectList(new LambdaQueryWrapperX() - .likeIfPresent(DeptDO::getFlag, deptDo.getFlag()) - .eq(DeptDO::getType, 0)); + List companyDeptList = deptMapper.selectCompany(deptDo.getFlag(), DeptTypeEnum.COMPANY.getValue()); if (CollectionUtil.isEmpty(companyDeptList)) { return new DeptDO(); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java index 53253125..f2280797 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordService.java @@ -56,5 +56,5 @@ public interface RentalItemsRecordService { * @param orderNo 订单编号 * @return 剩余数量 */ - List getRentalItemsCount(String orderNo); + List getRentalItemsCount(String orderNo, Boolean isUpdate); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java index 3301cd6d..0bfcab9f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalItemsRecordServiceImpl.java @@ -39,7 +39,7 @@ public class RentalItemsRecordServiceImpl implements RentalItemsRecordService{ public Long createRentalItemsRecord(RentalItemsRecordSaveReqVO createReqVO) { // 获取订单剩余租借数量 使用悲观锁 - List reqVOS = getRentalItemsCount(createReqVO.getOrderNo()); + List reqVOS = getRentalItemsCount(createReqVO.getOrderNo(), true); Map countMap = convertMap(reqVOS, RentalItemsCountReqVO::getRentalItemsType); // 判断租借类型为归还时,检验归还数量是否大于剩余数量 @@ -58,7 +58,7 @@ public class RentalItemsRecordServiceImpl implements RentalItemsRecordService{ public void createRentalItemsRecordBath(List createReqVO) { // 获取订单剩余租借数量 使用悲观锁 - List reqVOS = getRentalItemsCount(createReqVO.get(0).getOrderNo()); + List reqVOS = getRentalItemsCount(createReqVO.get(0).getOrderNo(), true); Map countMap = convertMap(reqVOS, RentalItemsCountReqVO::getRentalItemsType); for (RentalItemsRecordSaveReqVO vo : createReqVO) { @@ -98,9 +98,9 @@ public class RentalItemsRecordServiceImpl implements RentalItemsRecordService{ } @Override - public List getRentalItemsCount(String orderNo) { + public List getRentalItemsCount(String orderNo, Boolean isUpdate) { - return rentalItemsRecordMapper.selectRentalItemsCount(orderNo); + return rentalItemsRecordMapper.selectRentalItemsCount(orderNo, isUpdate); } private void validateRentalItemsRecordExists(Long id) { diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/dept/DeptMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/dept/DeptMapper.xml new file mode 100644 index 00000000..4ed0e5c3 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/dept/DeptMapper.xml @@ -0,0 +1,22 @@ + + + + + + + + \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml index 0abb1b9b..3315f9c4 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml @@ -19,6 +19,8 @@ WHERE order_no = #{orderNo} AND deleted = 0 - FOR UPDATE + + FOR UPDATE + From e26f51b98251780cf9bee1987c1a57453d76d70a Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Wed, 27 Nov 2024 09:23:07 +0800 Subject: [PATCH 15/18] =?UTF-8?q?feat(rental):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E7=A7=9F=E8=B5=81=E8=AE=A2=E5=8D=95=E9=80=80=E6=AC=BE=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=B9=B6=E6=96=B0=E5=A2=9E=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增租赁订单物品记录相关接口和DTO - 完善租赁订单状态管理和退款流程- 新增获取租赁订单信息接口 - 优化租赁订单列表展示,增加退款申请信息 --- .../api/rental/RentalDepositRecordApi.java | 3 +- .../api/rental/RentalItemsRecordApi.java | 28 +++++++++++++++ .../system/api/rental/RentalOrderApi.java | 5 +++ .../api/rental/dto/RentalItemsRecordDTO.java | 32 +++++++++++++++++ .../rental/RentalDepositRecordApiImpl.java | 9 +++-- .../api/rental/RentalItemsRecordApiImpl.java | 35 +++++++++++++++++++ .../system/api/rental/RentalOrderApiImpl.java | 9 ++++- .../admin/rental/RentalOrderController.java | 26 ++++++++++++++ .../rental/vo/order/RentalOrderRespVO.java | 6 ++++ .../RentalDepositRecordSaveReqVO.java | 3 ++ .../dal/dataobject/rental/RentalOrderDO.java | 17 +++++++++ .../rpc/config/RpcConfiguration.java | 7 ++-- .../RentalDepositRecordServiceImpl.java | 25 +++++++++++-- .../service/rental/RentalOrderService.java | 10 +++++- .../rental/RentalOrderServiceImpl.java | 14 +++++--- .../mapper/rental/RentalItemsRecordMapper.xml | 2 ++ 16 files changed, 215 insertions(+), 16 deletions(-) create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApi.java create mode 100644 yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalItemsRecordDTO.java create mode 100644 yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApiImpl.java diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApi.java index bcca9566..6e594235 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApi.java @@ -12,6 +12,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestParam; import java.math.BigDecimal; +import java.util.Map; @FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = @Tag(name = "RPC 服务 - 租赁订单金额记录") @@ -25,5 +26,5 @@ public interface RentalDepositRecordApi { @GetMapping(PREFIX + "/getRecordAmount") @Operation(summary = "获取租赁订单已收取的金额") - CommonResult getRecordAmount(@RequestParam("orderNo") String orderNo); + CommonResult> getRecordAmount(@RequestParam("orderNo") String orderNo); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApi.java new file mode 100644 index 00000000..e48652f0 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApi.java @@ -0,0 +1,28 @@ +package cn.iocoder.yudao.module.system.api.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalDepositRecordDTO; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalItemsRecordDTO; +import cn.iocoder.yudao.module.system.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 租赁订单物品记录") +public interface RentalItemsRecordApi { + + String PREFIX = ApiConstants.PREFIX + "/rental-items"; + + @PutMapping(PREFIX + "/create") + @Operation(summary = "创建租赁订单出入库记录") + CommonResult create(@RequestBody List createReqVO); +} diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java index 1b6eaff9..aaaf45f8 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java @@ -22,4 +22,9 @@ public interface RentalOrderApi { @PutMapping(PREFIX + "/update") @Operation(summary = "更新租赁订单信息") CommonResult updateOrder(@RequestBody RentalOrderDTO updateReqVO); + + @GetMapping(PREFIX + "/get") + @Operation(summary = "获取租赁订单信息") + @Parameter(name = "orderNo", description = "订单编号", required = true) + CommonResult getOrder(@RequestParam("orderNo") String orderNo); } diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalItemsRecordDTO.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalItemsRecordDTO.java new file mode 100644 index 00000000..2b69e245 --- /dev/null +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/dto/RentalItemsRecordDTO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.system.api.rental.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; + +@Schema(description = "管理后台 - 租赁物品记录新增/修改 Request VO") +@Data +public class RentalItemsRecordDTO { + + @Schema(description = "租赁订单表单主键") + private Long id; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + @NotEmpty(message = "订单编号不能为空") + private String orderNo; + + @Schema(description = "租赁物品种类 | 字典值参考 system_rental_items_type", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "租赁物品种类不能为空") + private Integer rentalItemsType; + + @Schema(description = "租赁数量", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "租赁数量不能为空") + private Integer number; + + @Schema(description = "类型 | 1租借 2归还", requiredMode = Schema.RequiredMode.REQUIRED) + @NotNull(message = "类型不能为空") + private Integer type; + +} \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java index d54d80ce..5a7b1dcf 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java @@ -16,6 +16,8 @@ import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; @@ -33,8 +35,11 @@ public class RentalDepositRecordApiImpl implements RentalDepositRecordApi { } @Override - public CommonResult getRecordAmount(String orderNo) { + public CommonResult> getRecordAmount(String orderNo) { RentalDepositAmountReqVO reqVO = rentalDepositRecordService.getRentalDepositRecordAmount(orderNo, false); - return success(reqVO.getReceivedAmount()); + Map result = new HashMap<>(); + result.put("receivedAmount", reqVO.getReceivedAmount()); + result.put("refundAmount", reqVO.getRefundAmount()); + return success(result); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApiImpl.java new file mode 100644 index 00000000..9776cd41 --- /dev/null +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApiImpl.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.system.api.rental; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalDepositRecordDTO; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalItemsRecordDTO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; +import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; +import cn.iocoder.yudao.module.system.service.rental.RentalDepositRecordService; +import cn.iocoder.yudao.module.system.service.rental.RentalItemsRecordService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@RestController // 提供 RESTful API 接口,给 Feign 调用 +@Validated +public class RentalItemsRecordApiImpl implements RentalItemsRecordApi { + + @Resource + private RentalItemsRecordService rentalItemsRecordService; + + @Override + public CommonResult create(List createReqVO) { + rentalItemsRecordService.createRentalItemsRecordBath(BeanUtils.toBean(createReqVO, RentalItemsRecordSaveReqVO.class)); + return success(true); + } +} diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java index 4615f26e..46f14c04 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.rental.dto.RentalOrderDTO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; import cn.iocoder.yudao.module.system.service.rental.RentalOrderService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; @@ -21,7 +22,13 @@ public class RentalOrderApiImpl implements RentalOrderApi { @Override public CommonResult updateOrder(RentalOrderDTO updateReqVO) { - rentalOrderService.update(BeanUtils.toBean(updateReqVO, RentalOrderSaveReqVO.class)); + rentalOrderService.update(BeanUtils.toBean(updateReqVO, RentalOrderDO.class)); return success(true); } + + @Override + public CommonResult getOrder(String orderNo) { + RentalOrderDO rentalOrder = rentalOrderService.getRentalOrder(orderNo); + return success(BeanUtils.toBean(rentalOrder, RentalOrderDTO.class)); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java index 9621d053..e6bf5304 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java @@ -1,11 +1,14 @@ package cn.iocoder.yudao.module.system.controller.admin.rental; +import cn.hutool.core.collection.CollectionUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; +import cn.iocoder.yudao.module.bpm.api.oa.BpmOARefundApi; +import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOARefundDTO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderRespVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; @@ -28,8 +31,12 @@ import javax.validation.Valid; import java.io.IOException; import java.math.BigDecimal; import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; @@ -48,6 +55,9 @@ public class RentalOrderController { @Resource private RentalDepositRecordService rentalDepositRecordService; + @Resource + private BpmOARefundApi refundApi; + @PostMapping("/create") @Operation(summary = "创建租赁订单") @PreAuthorize("@ss.hasPermission('system:rental-order:create')") @@ -103,6 +113,22 @@ public class RentalOrderController { @PreAuthorize("@ss.hasPermission('system:rental-order:query')") public CommonResult> getRentalOrderPage(@Valid RentalOrderPageReqVO pageReqVO) { PageResult pageResult = rentalOrderService.getRentalOrderPage(pageReqVO); + // 获取等待退款的订单号 + List orderNos = pageResult.getList().stream() + .filter(item -> Objects.equals(item.getStatus(), RentalOrderDO.WAITING_FOR_REFUND)) + .map(RentalOrderRespVO::getOrderNo) + .collect(Collectors.toList()); + // 获取订单号对应的退款申请 + Map refundMap = refundApi.getListByOrderNo(orderNos).getCheckedData(); + + if (CollectionUtil.isNotEmpty(refundMap)) { + // 设置对应的订单号中的 申请退款和扣款金额 + pageResult.getList().forEach(item -> { + item.setApplyRefundAmount(refundMap.get(item.getOrderNo()).getRefundAmount()); + item.setApplyChargebacksAmount(refundMap.get(item.getOrderNo()).getChargebacksAmount()); + }); + } + return success(pageResult); } } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java index c0e54065..faa81133 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/order/RentalOrderRespVO.java @@ -43,6 +43,12 @@ public class RentalOrderRespVO { @Schema(description = "扣款金额") private BigDecimal chargebacksAmount; + @Schema(description = "申请退款金额") + private BigDecimal applyRefundAmount; + + @Schema(description = "申请扣款金额") + private BigDecimal applyChargebacksAmount; + @Schema(description = "备注") private String notes; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java index 3584c892..9fe4495b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/vo/rentaldepositrecord/RentalDepositRecordSaveReqVO.java @@ -40,6 +40,9 @@ public class RentalDepositRecordSaveReqVO { @NotNull(message = "收款/退款金额不能为空") private BigDecimal amount; + @Schema(description = "扣款金额") + private BigDecimal chargebacksAmount; + @Schema(description = "收款/退款日期", requiredMode = Schema.RequiredMode.REQUIRED) @NotNull(message = "收款/退款日期不能为空") private LocalDate paymentDate; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java index a19d4f68..42aa8dab 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java @@ -23,6 +23,23 @@ import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; @AllArgsConstructor public class RentalOrderDO extends BaseDO { + /** + * 状态 1 租赁中 + */ + public static final Integer ON_LEASE = 1; + /** + * 状态 2 退款申请中 + */ + public static final Integer REFUND_REQUESTED = 2; + /** + * 状态 3 等待退款中 + */ + public static final Integer WAITING_FOR_REFUND = 3; + /** + * 状态 4 已退款 + */ + public static final Integer REFUNDED = 4; + /** * 租赁订单表单主键 */ diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/rpc/config/RpcConfiguration.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/rpc/config/RpcConfiguration.java index fbb92e46..eb5fed4f 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/rpc/config/RpcConfiguration.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/framework/rpc/config/RpcConfiguration.java @@ -1,10 +1,7 @@ package cn.iocoder.yudao.module.system.framework.rpc.config; import cn.iocoder.yudao.module.bpm.api.model.BpmModelApi; -import cn.iocoder.yudao.module.bpm.api.oa.BpmOAEntryApi; -import cn.iocoder.yudao.module.bpm.api.oa.BpmOAEvectionApi; -import cn.iocoder.yudao.module.bpm.api.oa.BpmOAGoOutApi; -import cn.iocoder.yudao.module.bpm.api.oa.BpmOAReplacementCardApi; +import cn.iocoder.yudao.module.bpm.api.oa.*; import cn.iocoder.yudao.module.infra.api.config.ConfigApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.infra.api.websocket.WebSocketSenderApi; @@ -14,6 +11,6 @@ import org.springframework.context.annotation.Configuration; @Configuration(proxyBeanMethods = false) @EnableFeignClients(clients = {FileApi.class, WebSocketSenderApi.class, FactoryInfoApi.class, BpmModelApi.class, BpmOAGoOutApi.class, BpmOAEntryApi.class, ConfigApi.class, - BpmOAEvectionApi.class, BpmOAReplacementCardApi.class}) + BpmOAEvectionApi.class, BpmOAReplacementCardApi.class, BpmOARefundApi.class}) public class RpcConfiguration { } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java index 9ae839bd..1704780c 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalDepositRecordServiceImpl.java @@ -3,14 +3,17 @@ package cn.iocoder.yudao.module.system.service.rental; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.api.oa.BpmOARefundApi; import cn.iocoder.yudao.module.infra.api.file.FileApi; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; +import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalDepositRecordMapper; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; @@ -40,7 +43,11 @@ public class RentalDepositRecordServiceImpl implements RentalDepositRecordServic @Resource private FileApi fileApi; + @Resource + private BpmOARefundApi refundApi; + @Override + @Transactional(rollbackFor = Exception.class) public Long createRentalDepositRecord(RentalDepositRecordSaveReqVO createReqVO) { // 获取当前订单的 剩余押金金额 @@ -60,11 +67,25 @@ public class RentalDepositRecordServiceImpl implements RentalDepositRecordServic } break; case 2: + RentalOrderDO updateOrder = new RentalOrderDO(); // 押金退款 - // 判断当前退款金额 大于 实际已收的金额时 - if (amount.compareTo(createReqVO.getAmount()) < 0) { + // 判断当前退款金额 + 扣款金额 大于 剩余已收金额时 + BigDecimal refundAmount = createReqVO.getAmount().add(createReqVO.getChargebacksAmount() == null ? BigDecimal.ZERO : createReqVO.getChargebacksAmount()); + if (amount.compareTo(refundAmount) < 0) { throw exception(RENTAL_REFUND_AMOUNT_EXCESS); + } else if (amount.compareTo(refundAmount) == 0) { // 判断当前退款金额 是否等于 实际已收的金额 - 扣款金额时 + // 更新订单状态为 已退款 + updateOrder.setOrderNo(createReqVO.getOrderNo()); + updateOrder.setStatus(RentalOrderDO.REFUNDED); + }else { // 判断当前退款金额 是否小于 实际已收的金额 - 扣款金额时 + // 更新订单状态为 租赁中 + updateOrder.setOrderNo(createReqVO.getOrderNo()); + updateOrder.setStatus(RentalOrderDO.ON_LEASE); } + // 同步更新 退款申请流程中的 退款状态 + refundApi.updateStatus(createReqVO.getOrderNo()); + // 同步更新 租赁订单状态 + rentalOrderService.update(updateOrder); break; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java index 62ee124e..a27348a6 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderService.java @@ -35,7 +35,7 @@ public interface RentalOrderService { * 更新租赁订单 * @param updateReqVO 更新信息 */ - void update(RentalOrderSaveReqVO updateReqVO); + void update(RentalOrderDO updateReqVO); /** * 删除租赁订单 @@ -52,6 +52,14 @@ public interface RentalOrderService { */ RentalOrderDO getRentalOrder(Long id); + /** + * 获得租赁订单 + * + * @param orderNo 订单编号 + * @return 租赁订单 + */ + RentalOrderDO getRentalOrder(String orderNo); + /** * 获得租赁订单分页 * diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java index c5fba014..2090e0d8 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java @@ -119,15 +119,14 @@ public class RentalOrderServiceImpl implements RentalOrderService { } @Override - public void update(RentalOrderSaveReqVO updateReqVO) { + public void update(RentalOrderDO updateReqVO) { Long count = rentalOrderMapper.selectCount(RentalOrderDO::getOrderNo, updateReqVO.getOrderNo()); if (count <= 0L) { throw exception(RENTAL_ORDER_NOT_EXISTS); } // 更新 - RentalOrderDO updateObj = BeanUtils.toBean(updateReqVO, RentalOrderDO.class); - rentalOrderMapper.update(updateObj, new LambdaQueryWrapperX() + rentalOrderMapper.update(updateReqVO, new LambdaQueryWrapperX() .eq(RentalOrderDO::getOrderNo, updateReqVO.getOrderNo())); } @@ -147,9 +146,16 @@ public class RentalOrderServiceImpl implements RentalOrderService { @Override public RentalOrderDO getRentalOrder(Long id) { + return rentalOrderMapper.selectById(id); } + @Override + public RentalOrderDO getRentalOrder(String orderNo) { + + return rentalOrderMapper.selectOne(RentalOrderDO::getOrderNo, orderNo); + } + @Override public PageResult getRentalOrderPage(RentalOrderPageReqVO pageReqVO) { return rentalOrderMapper.selectPage(pageReqVO); @@ -158,7 +164,7 @@ public class RentalOrderServiceImpl implements RentalOrderService { @Override @Cacheable(value = RedisKeyConstants.RENTAL_ORDER_AMOUNT, key = "#orderNo", unless = "#result == null") public BigDecimal getOrderAmount(String orderNo) { + return rentalOrderMapper.selectOrderAmount(orderNo); } - } \ No newline at end of file diff --git a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml index 3315f9c4..53c84029 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml +++ b/yudao-module-system/yudao-module-system-biz/src/main/resources/mapper/rental/RentalItemsRecordMapper.xml @@ -19,6 +19,8 @@ WHERE order_no = #{orderNo} AND deleted = 0 + GROUP BY + rental_items_type FOR UPDATE From 61b452815408bbef6d51dd0442ecfd6e127991dd Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Wed, 27 Nov 2024 09:25:05 +0800 Subject: [PATCH 16/18] =?UTF-8?q?feat(rental):=20=E5=AE=8C=E5=96=84?= =?UTF-8?q?=E7=A7=9F=E8=B5=81=E8=AE=A2=E5=8D=95=E9=80=80=E6=AC=BE=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=E5=B9=B6=E6=96=B0=E5=A2=9E=E7=9B=B8=E5=85=B3=E6=8E=A5?= =?UTF-8?q?=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增租赁订单物品记录相关接口和DTO - 完善租赁订单状态管理和退款流程- 新增获取租赁订单信息接口 - 优化租赁订单列表展示,增加退款申请信息 --- .../module/bpm/api/oa/BpmOARefundApi.java | 33 +++++++++++ .../module/bpm/api/oa/vo/BpmOARefundDTO.java | 50 ++++++++++++++++ .../module/bpm/api/oa/BpmOARefundApiImpl.java | 39 +++++++++++++ .../oa/vo/refund/BpmOARefundCreateReqVO.java | 3 + .../admin/oa/vo/refund/BpmOARefundRespVO.java | 3 + .../bpm/dal/dataobject/oa/BpmOARefundDO.java | 5 ++ .../bpm/dal/mysql/oa/BpmOAEvectionMapper.java | 6 +- .../rpc/config/RpcConfiguration.java | 3 +- .../bpm/service/oa/BpmOARefundService.java | 26 +++++++-- .../service/oa/BpmOARefundServiceImpl.java | 58 +++++++++++++++++-- .../rental/RentalDepositRecordApiImpl.java | 5 -- .../api/rental/RentalItemsRecordApiImpl.java | 7 --- .../system/api/rental/RentalOrderApiImpl.java | 1 - .../admin/rental/RentalOrderController.java | 7 --- .../dal/dataobject/rental/RentalOrderDO.java | 8 +-- .../rental/RentalOrderServiceImpl.java | 3 - 16 files changed, 216 insertions(+), 41 deletions(-) create mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/BpmOARefundApi.java create mode 100644 yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/vo/BpmOARefundDTO.java create mode 100644 yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/BpmOARefundApiImpl.java diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/BpmOARefundApi.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/BpmOARefundApi.java new file mode 100644 index 00000000..a4246e9f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/BpmOARefundApi.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.bpm.api.oa; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOARefundDTO; +import cn.iocoder.yudao.module.bpm.enums.ApiConstants; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.cloud.openfeign.FeignClient; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; +import java.util.Map; + +@FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = +@Tag(name = "RPC 服务 - 退款申请") +public interface BpmOARefundApi { + + String PREFIX = ApiConstants.PREFIX + "/oa/refund"; + + @PostMapping(PREFIX + "/get") + @Operation(summary = "获得指定的退款申请列表") + CommonResult> getListByOrderNo(@RequestBody List orderNos); + + @GetMapping(PREFIX + "/update-status") + @Operation(summary = "修改退款申请的退款状态 为已退款") + @Parameter(name = "orderNo", description = "订单编号", required = true) + @Parameter(name = "status", description = "状态", required = true) + CommonResult updateStatus(@RequestParam("orderNo") String orderNo); +} diff --git a/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/vo/BpmOARefundDTO.java b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/vo/BpmOARefundDTO.java new file mode 100644 index 00000000..443a8d5f --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-api/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/vo/BpmOARefundDTO.java @@ -0,0 +1,50 @@ +package cn.iocoder.yudao.module.bpm.api.oa.vo; + +import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.ToString; +import org.springframework.format.annotation.DateTimeFormat; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; + +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY; + +/** + * @author 符溶馨 + */ +@Schema(description = "管理后台 - 退款申请 请求Request VO") +@Data +@ToString(callSuper = true) +public class BpmOARefundDTO { + + @Schema(description = "表单主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") + private Long id; + + @Schema(description = "状态-参见 bpm_process_instance_result 枚举", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer result; + + @Schema(description = "流程id") + private String processInstanceId; + + @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED) + private String orderNo; + + @Schema(description = "扣款金额") + private BigDecimal chargebacksAmount; + + @Schema(description = "退款金额", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private BigDecimal refundAmount; + + @Schema(description = "退款日期", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY) + private LocalDate refundDate; + + @Schema(description = "备注", requiredMode = Schema.RequiredMode.NOT_REQUIRED) + private String notes; + + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) + private List fileItems; +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/BpmOARefundApiImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/BpmOARefundApiImpl.java new file mode 100644 index 00000000..257625b7 --- /dev/null +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/api/oa/BpmOARefundApiImpl.java @@ -0,0 +1,39 @@ +package cn.iocoder.yudao.module.bpm.api.oa; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOARefundDTO; +import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOARefundDO; +import cn.iocoder.yudao.module.bpm.service.oa.BpmOARefundService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; + +/** + * Flowable 流程实例 Api 实现类 + */ +@RestController +@Validated +public class BpmOARefundApiImpl implements BpmOARefundApi{ + + @Resource + private BpmOARefundService refundService; + + @Override + public CommonResult> getListByOrderNo(List orderNos) { + List list = refundService.getListByOrderNo(orderNos); + return success(convertMap(BeanUtils.toBean(list, BpmOARefundDTO.class), BpmOARefundDTO::getOrderNo)); + } + + @Override + public CommonResult updateStatus(String orderNo) { + refundService.updateStatus(orderNo); + return success(true); + } +} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundCreateReqVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundCreateReqVO.java index 0d583a3f..7f5fae0a 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundCreateReqVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundCreateReqVO.java @@ -47,6 +47,9 @@ public class BpmOARefundCreateReqVO { @Schema(description = "备注", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String notes; + @Schema(description = "状态 | 0未退款 1已退款", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + @Schema(description = "流程实例编号") private String processInstanceId; diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundRespVO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundRespVO.java index ca4ea576..9e857180 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundRespVO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/oa/vo/refund/BpmOARefundRespVO.java @@ -46,6 +46,9 @@ public class BpmOARefundRespVO extends BpmOABaseRespVO { @Schema(description = "备注", requiredMode = Schema.RequiredMode.NOT_REQUIRED) private String notes; + @Schema(description = "状态 | 0未退款 1已退款", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + private Integer status; + @Schema(description = "上传文件", requiredMode = Schema.RequiredMode.REQUIRED) private List fileItems; } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java index f0e4d2c9..84c5c5f8 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/dataobject/oa/BpmOARefundDO.java @@ -71,6 +71,11 @@ public class BpmOARefundDO extends BaseDO { */ private String notes; + /** + * 状态 | 0未退款 1已退款 + */ + private Integer status; + /** * 结果 * 枚举 {@link BpmProcessInstanceResultEnum} diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAEvectionMapper.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAEvectionMapper.java index a81c7616..ee3e6fae 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAEvectionMapper.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/dal/mysql/oa/BpmOAEvectionMapper.java @@ -4,8 +4,11 @@ import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.evection.BpmOAEvectionCreateReqVO; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAEvectionDO; +import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import org.apache.ibatis.annotations.Mapper; +import java.util.Arrays; + /** * 出差申请 Mapper * @@ -20,6 +23,7 @@ public interface BpmOAEvectionMapper extends BaseMapperX { return selectCount(new LambdaQueryWrapperX() .eq(BpmOAEvectionDO::getUserId, userId) .leIfPresent(BpmOAEvectionDO::getStartTime, createReqVO.getEndTime()) - .geIfPresent(BpmOAEvectionDO::getEndTime, createReqVO.getStartTime())); + .geIfPresent(BpmOAEvectionDO::getEndTime, createReqVO.getStartTime()) + .in(BpmOAEvectionDO::getResult, Arrays.asList(BpmProcessInstanceResultEnum.PROCESS, BpmProcessInstanceResultEnum.APPROVE))); } } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java index dbab845c..74d9e08f 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/rpc/config/RpcConfiguration.java @@ -18,6 +18,7 @@ import cn.iocoder.yudao.module.system.api.permission.RoleApi; import cn.iocoder.yudao.module.system.api.position.PositionApi; import cn.iocoder.yudao.module.system.api.project.ProjectApi; import cn.iocoder.yudao.module.system.api.rental.RentalDepositRecordApi; +import cn.iocoder.yudao.module.system.api.rental.RentalItemsRecordApi; import cn.iocoder.yudao.module.system.api.rental.RentalOrderApi; import cn.iocoder.yudao.module.system.api.sms.SmsSendApi; import cn.iocoder.yudao.module.system.api.social.SocialClientApi; @@ -32,7 +33,7 @@ import org.springframework.context.annotation.Configuration; @EnableFeignClients(clients = {FileApi.class, RoleApi.class, DeptApi.class, PostApi.class, AdminUserApi.class, SmsSendApi.class, DictDataApi.class, NotifyMessageSendApi.class, SubscribeMessageSendApi.class, SocialClientApi.class, UsersExtApi.class, AttendanceApi.class, BankApi.class, ConfigApi.class, PositionApi.class, SupplierApi.class, AssetsApi.class, AssetsTypeApi.class, AssetReceiveApi.class, AttendanceApi.class, AttendanceGroupApi.class, WorkOvertimeApi.class, HolidayApi.class, - RentalOrderApi.class, RentalDepositRecordApi.class, ProjectApi.class + RentalOrderApi.class, RentalDepositRecordApi.class, ProjectApi.class, RentalItemsRecordApi.class }) public class RpcConfiguration { } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundService.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundService.java index 9893d910..227d0e25 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundService.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundService.java @@ -4,11 +4,12 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund.BpmOARefundCrea import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOARefundDO; import javax.validation.Valid; +import java.util.List; public interface BpmOARefundService { /** - * 创建转正申请 + * 创建退款申请 * * @param userId 用户编号 * @param createReqVO 创建信息 @@ -17,7 +18,7 @@ public interface BpmOARefundService { Long createRefund(Long userId, @Valid BpmOARefundCreateReqVO createReqVO); /** - * 更新转正申请的状态 + * 更新退款申请的状态 * * @param id 编号 * @param result 结果 @@ -25,17 +26,30 @@ public interface BpmOARefundService { void updateRefundResult(String processInstanceId, Long id, Integer result); /** - * 获得转正申请 + * 获得退款申请 * * @param id 编号 - * @return 转正申请 + * @return 退款申请 */ BpmOARefundDO getRefund(Long id); /** - * 获得指定的转正申请 + * 获得指定的退款申请 * @param processInstanceId 流程实例编号 - * @return 转正申请 + * @return 退款申请 */ BpmOARefundDO getByProcessInstanceId(String processInstanceId); + + /** + * 获得指定的退款申请列表 + * @param orderNos 订单编号 + * @return 退款申请列表 + */ + List getListByOrderNo(List orderNos); + + /** + * 更新退款申请状态 + * @param orderNo 订单编号 + */ + void updateStatus(String orderNo); } diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java index dea81fff..37982d64 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/oa/BpmOARefundServiceImpl.java @@ -1,18 +1,24 @@ package cn.iocoder.yudao.module.bpm.service.oa; import cn.iocoder.yudao.framework.common.pojo.UploadUserFile; +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; +import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.bpm.api.task.BpmProcessInstanceApi; import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO; import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund.BpmOARefundCreateReqVO; +import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.refund.BpmOARefundItems; import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOARefundDO; import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOARefundMapper; import cn.iocoder.yudao.module.bpm.enums.task.BpmProcessInstanceResultEnum; import cn.iocoder.yudao.module.bpm.service.task.BpmHistoryProcessInstanceService; import cn.iocoder.yudao.module.bpm.service.task.BpmProcessInstanceService; import cn.iocoder.yudao.module.system.api.rental.RentalDepositRecordApi; +import cn.iocoder.yudao.module.system.api.rental.RentalItemsRecordApi; import cn.iocoder.yudao.module.system.api.rental.RentalOrderApi; +import cn.iocoder.yudao.module.system.api.rental.dto.RentalItemsRecordDTO; import cn.iocoder.yudao.module.system.api.rental.dto.RentalOrderDTO; +import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.flowable.engine.runtime.ProcessInstance; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -22,6 +28,7 @@ import java.math.BigDecimal; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_REFUND_NOT_EXISTS; @@ -57,13 +64,16 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef @Resource private RentalOrderApi rentalOrderApi; + @Resource + private RentalItemsRecordApi rentalItemsRecordApi; + @Resource private RentalDepositRecordApi depositRecordApi; @Override public Long createRefund(Long userId, BpmOARefundCreateReqVO createReqVO) { - // 发起流程前 校验扣款金额+退款金额是否等于已收金额 + // 发起流程前 校验扣款金额+退款金额是否大于已收金额 validateRefundAmount(createReqVO.getOrderNo(), createReqVO.getChargebacksAmount(), createReqVO.getRefundAmount()); //插入OA 退款申请 @@ -102,12 +112,16 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef } /** - * 校验扣款金额+退款金额是否等于已收金额 + * 校验扣款金额+退款金额是否大于已收金额 */ private void validateRefundAmount(String orderNo, BigDecimal chargebacksAmount, BigDecimal refundAmount) { - BigDecimal recordAmount = depositRecordApi.getRecordAmount(orderNo).getCheckedData(); - if (recordAmount.compareTo(chargebacksAmount.add(refundAmount)) != 0) { + // 获取订单的已收金额 和 已退金额 + Map respVO = depositRecordApi.getRecordAmount(orderNo).getCheckedData(); + // 获取当前订单 还需退款金额 = 已收金额 - 已退金额 + BigDecimal recordAmount = respVO.get("receivedAmount").subtract(respVO.get("refundAmount")); + + if (recordAmount.compareTo(chargebacksAmount.add(refundAmount)) < 0) { throw exception(RENTAL_REFUND_AMOUNT_EXCESS); } } @@ -123,11 +137,30 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef if (instance.isEnded()) { + // 获取订单的扣款金额 + BigDecimal chargebacks = rentalOrderApi.getOrder(refundDO.getOrderNo()).getCheckedData().getChargebacksAmount(); + // 审批通过后 更新租赁订单信息 rentalOrderApi.updateOrder(new RentalOrderDTO() .setOrderNo(refundDO.getOrderNo()) - .setChargebacksAmount(refundDO.getChargebacksAmount()) + .setChargebacksAmount(refundDO.getChargebacksAmount().add(chargebacks)) // 扣款金额累加 .setStatus(3)); // 状态变更为 等待退款中 + + List items = refundDO.getRefundItems(); + //直接从数据库取出来的List 实际上是List类型 所以不能直接遍历 + //将list再次转为json串,然后由json串再转为list + String json = JsonUtils.toJsonString(items); + items = JsonUtils.parseArray(json, BpmOARefundItems.class); + + // 审批通过后 更新租赁物品 归还信息 + List createReqVO = items.stream() + .map(item -> new RentalItemsRecordDTO() + .setOrderNo(refundDO.getOrderNo()) + .setRentalItemsType(item.getRentalItemsType()) + .setNumber(item.getRentalNumber()) + .setType(2)) + .collect(Collectors.toList()); + rentalItemsRecordApi.create(createReqVO); } } @@ -165,4 +198,19 @@ public class BpmOARefundServiceImpl extends BpmOABaseService implements BpmOARef return refundMapper.selectOne(BpmOARefundDO::getProcessInstanceId, processInstanceId); } + + @Override + public List getListByOrderNo(List orderNos) { + return refundMapper.selectList(new LambdaQueryWrapperX() + .inIfPresent(BpmOARefundDO::getOrderNo, orderNos) + .eq(BpmOARefundDO::getStatus, 0)); + } + + @Override + public void updateStatus(String orderNo) { + refundMapper.update(null, new LambdaUpdateWrapper() + .set(BpmOARefundDO::getStatus, 1) + .eq(BpmOARefundDO::getOrderNo, orderNo) + .eq(BpmOARefundDO::getStatus, 0)); + } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java index 5a7b1dcf..ddac2d14 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalDepositRecordApiImpl.java @@ -3,18 +3,13 @@ package cn.iocoder.yudao.module.system.api.rental; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.rental.dto.RentalDepositRecordDTO; -import cn.iocoder.yudao.module.system.api.rental.dto.RentalOrderDTO; -import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; -import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalDepositRecordDO; import cn.iocoder.yudao.module.system.service.rental.RentalDepositRecordService; -import cn.iocoder.yudao.module.system.service.rental.RentalOrderService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; - import java.math.BigDecimal; import java.util.HashMap; import java.util.Map; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApiImpl.java index 9776cd41..a2558243 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApiImpl.java @@ -2,21 +2,14 @@ package cn.iocoder.yudao.module.system.api.rental; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.module.system.api.rental.dto.RentalDepositRecordDTO; import cn.iocoder.yudao.module.system.api.rental.dto.RentalItemsRecordDTO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.itemsrecord.RentalItemsRecordSaveReqVO; -import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositAmountReqVO; -import cn.iocoder.yudao.module.system.controller.admin.rental.vo.rentaldepositrecord.RentalDepositRecordSaveReqVO; -import cn.iocoder.yudao.module.system.service.rental.RentalDepositRecordService; import cn.iocoder.yudao.module.system.service.rental.RentalItemsRecordService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; -import java.math.BigDecimal; -import java.util.HashMap; import java.util.List; -import java.util.Map; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java index 46f14c04..26d89df2 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApiImpl.java @@ -3,7 +3,6 @@ package cn.iocoder.yudao.module.system.api.rental; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.module.system.api.rental.dto.RentalOrderDTO; -import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderSaveReqVO; import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; import cn.iocoder.yudao.module.system.service.rental.RentalOrderService; import org.springframework.validation.annotation.Validated; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java index e6bf5304..1b44dddf 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/rental/RentalOrderController.java @@ -2,11 +2,8 @@ package cn.iocoder.yudao.module.system.controller.admin.rental; import cn.hutool.core.collection.CollectionUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; -import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog; import cn.iocoder.yudao.module.bpm.api.oa.BpmOARefundApi; import cn.iocoder.yudao.module.bpm.api.oa.vo.BpmOARefundDTO; import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrderPageReqVO; @@ -26,9 +23,7 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; -import javax.servlet.http.HttpServletResponse; import javax.validation.Valid; -import java.io.IOException; import java.math.BigDecimal; import java.util.List; import java.util.Map; @@ -36,8 +31,6 @@ import java.util.Objects; import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; -import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT; @Tag(name = "管理后台 - 租赁订单") diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java index 42aa8dab..f27936ce 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/dal/dataobject/rental/RentalOrderDO.java @@ -1,13 +1,11 @@ package cn.iocoder.yudao.module.system.dal.dataobject.rental; +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; import lombok.*; import java.math.BigDecimal; -import java.util.*; -import java.time.LocalDateTime; -import java.time.LocalDateTime; -import com.baomidou.mybatisplus.annotation.*; -import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; /** * 租赁订单 DO diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java index 2090e0d8..5145839b 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/rental/RentalOrderServiceImpl.java @@ -10,8 +10,6 @@ import cn.iocoder.yudao.module.system.controller.admin.rental.vo.order.RentalOrd import cn.iocoder.yudao.module.system.dal.dataobject.rental.RentalOrderDO; import cn.iocoder.yudao.module.system.dal.mysql.rental.RentalOrderMapper; import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import lombok.extern.slf4j.Slf4j; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; @@ -26,7 +24,6 @@ import javax.annotation.Resource; import java.math.BigDecimal; import java.time.LocalDate; import java.time.format.DateTimeFormatter; -import java.util.Objects; import java.util.concurrent.TimeUnit; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; From abbea8026b376974e136217e1ee04b30a2713be4 Mon Sep 17 00:00:00 2001 From: furongxin <419481438@qq.com> Date: Wed, 27 Nov 2024 11:44:29 +0800 Subject: [PATCH 17/18] =?UTF-8?q?refactor(system):=20=E7=A7=9F=E8=B5=81?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E7=9B=B8=E5=85=B3=20API=20=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E7=B2=BE=E7=AE=80-=20=E7=A7=BB=E9=99=A4=E4=BA=86=20RentalItems?= =?UTF-8?q?RecordApi=20=E5=92=8C=20RentalOrderApi=20=E4=B8=AD=E6=9C=AA?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=20import=20=E8=AF=AD=E5=8F=A5=20-?= =?UTF-8?q?=20=E5=88=A0=E9=99=A4=E4=BA=86=20RentalItemsRecordApi=20?= =?UTF-8?q?=E4=B8=AD=E6=9C=AA=E4=BD=BF=E7=94=A8=E7=9A=84=20FeignClient=20f?= =?UTF-8?q?allbackFactory=20=E9=85=8D=E7=BD=AE=20-=20=E6=B8=85=E7=90=86?= =?UTF-8?q?=E4=BA=86=E6=8E=A5=E5=8F=A3=E4=B8=AD=E7=9A=84=E5=86=97=E4=BD=99?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yudao/module/system/api/rental/RentalItemsRecordApi.java | 5 ----- .../yudao/module/system/api/rental/RentalOrderApi.java | 1 - 2 files changed, 6 deletions(-) diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApi.java index e48652f0..94422779 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalItemsRecordApi.java @@ -1,20 +1,15 @@ package cn.iocoder.yudao.module.system.api.rental; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.system.api.rental.dto.RentalDepositRecordDTO; import cn.iocoder.yudao.module.system.api.rental.dto.RentalItemsRecordDTO; import cn.iocoder.yudao.module.system.enums.ApiConstants; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestParam; -import java.math.BigDecimal; import java.util.List; -import java.util.Map; @FeignClient(name = ApiConstants.NAME) // TODO 芋艿:fallbackFactory = @Tag(name = "RPC 服务 - 租赁订单物品记录") diff --git a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java index aaaf45f8..36c762fb 100644 --- a/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java +++ b/yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/rental/RentalOrderApi.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.module.system.api.rental; import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.module.system.api.position.dto.PositionDTO; import cn.iocoder.yudao.module.system.api.rental.dto.RentalOrderDTO; import cn.iocoder.yudao.module.system.enums.ApiConstants; import io.swagger.v3.oas.annotations.Operation; From a12e01992fddb43b512ae98ab55bebd0fa6e6d1c Mon Sep 17 00:00:00 2001 From: Echo <4759156@qq.com> Date: Thu, 28 Nov 2024 11:07:38 +0800 Subject: [PATCH 18/18] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E5=AE=A1=E6=89=B9?= =?UTF-8?q?=E6=97=B6=E6=95=88=E6=8E=92=E8=A1=8C=E6=A6=9CSQL=20-=20?= =?UTF-8?q?=E6=9F=A5=E8=AF=A2=E5=B7=B2=E5=85=B3=E9=97=AD=E7=9A=84=E7=94=A8?= =?UTF-8?q?=E6=88=B7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../task/BpmProcessInstanceExtMapper.xml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmProcessInstanceExtMapper.xml b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmProcessInstanceExtMapper.xml index f260a1c1..c7a94d66 100644 --- a/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmProcessInstanceExtMapper.xml +++ b/yudao-module-bpm/yudao-module-bpm-biz/src/main/resources/mapper/task/BpmProcessInstanceExtMapper.xml @@ -50,15 +50,17 @@