feat(erp/timesheet): 新增工时填报管理模块审批功能

dev
Yangk 6 days ago
parent 0815706c2c
commit a9db3088c5

@ -113,4 +113,14 @@ public class ErpTimesheetInfoController extends BaseController {
return R.ok(list);
}
/**
*
*/
@SaCheckPermission("oa/erp:timesheetInfo:add")
@Log(title = "工时填报", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/submitAndFlowStart")
public R<ErpTimesheetInfoVo> submitAndFlowStart(@Validated(AddGroup.class) @RequestBody ErpTimesheetInfoBo bo) {
return R.ok(erpTimesheetInfoService.submitAndFlowStart(bo));
}
}

@ -64,5 +64,10 @@ public class ErpTimesheetDept extends TenantEntity {
@TableLogic
private String delFlag;
/**
* ID
*/
private Long approverId;
}

@ -74,5 +74,9 @@ public class ErpTimesheetProject extends TenantEntity {
@TableLogic
private String delFlag;
/**
* ID
*/
private Long approverId;
}

@ -57,5 +57,10 @@ public class ErpTimesheetDeptBo extends BaseEntity {
*/
private Long hours;
/**
* ID
*/
private Long approverId;
}

@ -8,6 +8,8 @@ import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
@ -64,17 +66,17 @@ public class ErpTimesheetInfoBo extends BaseEntity {
/**
*
*/
private Long totalHours;
private BigDecimal totalHours;
/**
*
*/
private Long deptHours;
private BigDecimal deptHours;
/**
*
*/
private Long projectHours;
private BigDecimal projectHours;
/**
* 1 2 3 4

@ -67,5 +67,10 @@ public class ErpTimesheetProjectBo extends BaseEntity {
*/
private Long hours;
/**
* ID
*/
private Long approverId;
}

@ -70,5 +70,10 @@ public class ErpTimesheetDeptVo implements Serializable {
@ExcelProperty(value = "工时")
private Long hours;
/**
* ID
*/
private Long approverId;
}

@ -100,8 +100,7 @@ public class ErpTimesheetInfoVo implements Serializable {
/**
*
*/
@ExcelProperty(value = "流程状态", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "flow_status")
@ExcelProperty(value = "流程状态")
private String flowStatus;
/**

@ -82,5 +82,10 @@ public class ErpTimesheetProjectVo implements Serializable {
@ExcelProperty(value = "工时")
private Long hours;
/**
* ID
*/
private Long approverId;
}

@ -1,9 +1,12 @@
package org.dromara.oa.erp.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.dromara.common.core.enums.BusinessStatusEnum;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
@ -14,6 +17,7 @@ import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.dromara.common.tenant.helper.TenantHelper;
import org.dromara.oa.erp.domain.ErpTimesheetDept;
import org.dromara.oa.erp.domain.ErpTimesheetProject;
import org.dromara.oa.erp.domain.bo.ErpTimesheetDeptBo;
@ -24,6 +28,8 @@ import org.dromara.oa.erp.service.IErpTimesheetDeptService;
import org.dromara.oa.erp.service.IErpTimesheetProjectService;
import org.dromara.workflow.api.RemoteWorkflowService;
import org.dromara.workflow.api.domain.RemoteStartProcess;
import org.dromara.workflow.api.event.ProcessEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
import org.dromara.oa.erp.domain.bo.ErpTimesheetInfoBo;
import org.dromara.oa.erp.domain.vo.ErpTimesheetInfoVo;
@ -32,10 +38,8 @@ import org.dromara.oa.erp.mapper.ErpTimesheetInfoMapper;
import org.dromara.oa.erp.service.IErpTimesheetInfoService;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.*;
import java.util.stream.Collectors;
/**
* Service
@ -45,6 +49,7 @@ import java.util.Collection;
*/
@RequiredArgsConstructor
@Service
@Slf4j
public class ErpTimesheetInfoServiceImpl implements IErpTimesheetInfoService {
private final ErpTimesheetInfoMapper baseMapper;
@ -240,42 +245,110 @@ public class ErpTimesheetInfoServiceImpl implements IErpTimesheetInfoService {
@Override
@GlobalTransactional(rollbackFor = Exception.class) // 开启全局事务
public ErpTimesheetInfoVo submitAndFlowStart(ErpTimesheetInfoBo bo) {
ErpTimesheetInfo add = MapstructUtils.convert(bo, ErpTimesheetInfo.class);
validEntityBeforeSave(add);
if (bo.getTimesheetId() == null) {
this.insertByBo(bo);
} else {
this.updateByBo(bo);
}
// 准备启动流程参数
// 后端发起需要忽略权限
if (bo.getVariables() == null) {
bo.setVariables(new HashMap<>());
}
bo.getVariables().put("ignore", true);
Map<String, Object> variables = bo.getVariables();
// --- 处理部门工时审批人 ---
List<ErpTimesheetDeptBo> deptList = bo.getTimesheetDeptList();
List<String> deptApprovers = new ArrayList<>();
if (CollUtil.isNotEmpty(deptList)) {
deptApprovers = deptList.stream()
.map(ErpTimesheetDeptBo::getApproverId)
.filter(Objects::nonNull)
.map(String::valueOf)
.distinct()
.collect(Collectors.toList());
}
// deptApprovers (审批人列表)
variables.put("deptApprovers", deptApprovers);
// hasDeptWork (是否有部门工时) - true/false
variables.put("hasDeptWork", CollUtil.isNotEmpty(deptApprovers));
// --- 处理项目工时审批人 ---
List<ErpTimesheetProjectBo> projectList = bo.getTimesheetProjectList();
List<String> projectApprovers = new ArrayList<>();
if (CollUtil.isNotEmpty(projectList)) {
projectApprovers = projectList.stream()
.map(ErpTimesheetProjectBo::getApproverId)
.filter(Objects::nonNull)
.map(String::valueOf)
.distinct()
.collect(Collectors.toList());
}
variables.put("projectApprovers", projectApprovers);
variables.put("hasProjectWork", CollUtil.isNotEmpty(projectApprovers));
RemoteStartProcess startProcess = new RemoteStartProcess();
startProcess.setBusinessId(bo.getTimesheetId().toString());
startProcess.setFlowCode(bo.getFlowCode());
startProcess.setVariables(bo.getVariables());
startProcess.setVariables(variables);
startProcess.setBizExt(bo.getBizExt());
// 确保 BizExt 里也有 BusinessId
if (bo.getBizExt() != null) {
bo.getBizExt().setBusinessId(startProcess.getBusinessId());
}
// 调用远程服务启动流程
// startCompleteTask 表示“启动并自动完成第一个发起节点”,直接流转到下一个审批人
boolean flagOne = remoteWorkflowService.startCompleteTask(startProcess);
if (!flagOne) {
boolean flag = remoteWorkflowService.startCompleteTask(startProcess);
if (!flag) {
throw new ServiceException("流程发起异常");
}
return MapstructUtils.convert(add, ErpTimesheetInfoVo.class);
return MapstructUtils.convert(baseMapper.selectById(bo.getTimesheetId()), ErpTimesheetInfoVo.class);
}
/**
* (: 稿退)
*
* @param processEvent
*/
@EventListener(condition = "#processEvent.flowCode == 'OATS'")
public void processHandler(ProcessEvent processEvent) {
TenantHelper.dynamic(processEvent.getTenantId(), () -> {
log.info("【工时填报流程监听】开始处理: key={}, status={}", processEvent.getFlowCode(), processEvent.getStatus());
Long timeSheetId = Convert.toLong(processEvent.getBusinessId());
ErpTimesheetInfo timeSheetInfo = baseMapper.selectById(timeSheetId);
if (timeSheetInfo == null) {
log.error("未找到对应的工时单据id={}", timeSheetId);
return;
}
timeSheetInfo.setFlowStatus(processEvent.getStatus());
String status = processEvent.getStatus();
// A. 审批中 (Waiting)
if (BusinessStatusEnum.WAITING.getStatus().equals(status)) {
timeSheetInfo.setTimesheetStatus("2");
}
// B. 流程结束/审批通过 (Finish)
else if (BusinessStatusEnum.FINISH.getStatus().equals(status)) {
timeSheetInfo.setTimesheetStatus("3");
}
// C. 驳回/撤销
else if (BusinessStatusEnum.BACK.getStatus().equals(status)
|| BusinessStatusEnum.CANCEL.getStatus().equals(status)) {
timeSheetInfo.setTimesheetStatus("1");
}
// D. 作废/终止
else if (BusinessStatusEnum.INVALID.getStatus().equals(status)
|| BusinessStatusEnum.TERMINATION.getStatus().equals(status)) {
timeSheetInfo.setTimesheetStatus("4");
}
baseMapper.updateById(timeSheetInfo);
});
}
}

Loading…
Cancel
Save