修复了已知问题以及报销合理化

This commit is contained in:
2026-07-08 18:12:31 +08:00
parent 948e94f425
commit 73564a0db6
37 changed files with 114 additions and 430 deletions

View File

@@ -72,24 +72,29 @@ public class HrmMyApplyController extends BaseController {
List<HrmMyApplyVo> all = new ArrayList<>();
if (bizType == null || bizType.isEmpty() || "leave".equals(bizType)) {
all.addAll(mapLeave(leaveReqMapper.selectVoWithProjectList(buildLeaveBo(emp.getEmpId(), status)), nickName));
all.addAll(mapLeave(leaveReqMapper.selectVoWithProjectList(buildLeaveBo(emp.getEmpId())), nickName));
}
if (bizType == null || bizType.isEmpty() || "travel".equals(bizType)) {
all.addAll(mapTravel(travelReqMapper.selectVoWithProjectList(buildTravelBo(emp.getEmpId(), status)), nickName));
all.addAll(mapTravel(travelReqMapper.selectVoWithProjectList(buildTravelBo(emp.getEmpId())), nickName));
}
if (bizType == null || bizType.isEmpty() || "seal".equals(bizType)) {
all.addAll(mapSeal(sealReqMapper.selectVoWithProjectList(buildSealBo(emp.getEmpId(), status)), nickName));
all.addAll(mapSeal(sealReqMapper.selectVoWithProjectList(buildSealBo(emp.getEmpId())), nickName));
}
if (bizType == null || bizType.isEmpty() || "reimburse".equals(bizType)) {
all.addAll(mapReimburse(reimburseReqMapper.selectVoWithProjectList(buildReimburseBo(emp.getEmpId(), status)), nickName));
all.addAll(mapReimburse(reimburseReqMapper.selectVoWithProjectList(buildReimburseBo(emp.getEmpId())), nickName));
}
if (bizType == null || bizType.isEmpty() || "appropriation".equals(bizType)) {
all.addAll(mapAppropriation(appropriationReqMapper.selectVoWithProjectList(buildAppropriationBo(emp.getEmpId(), status)), nickName));
all.addAll(mapAppropriation(appropriationReqMapper.selectVoWithProjectList(buildAppropriationBo(emp.getEmpId())), nickName));
}
// 用流程实例状态覆盖业务表状态,避免历史数据状态未同步
// 状态唯一来源:流程实例表 hrm_flow_instance
overrideStatusByFlowInstance(all);
// 状态过滤放到实例覆盖之后(业务表已无 status 字段可下推)
if (status != null && !status.isEmpty()) {
all = all.stream().filter(v -> status.equalsIgnoreCase(v.getStatus())).collect(Collectors.toList());
}
if (keyword != null && !keyword.isEmpty()) {
String lower = keyword.toLowerCase();
all = all.stream().filter(v -> contains(v, lower)).collect(Collectors.toList());
@@ -157,27 +162,26 @@ public class HrmMyApplyController extends BaseController {
|| Objects.toString(v.getBizId(), "").contains(lower);
}
private HrmLeaveReqBo buildLeaveBo(Long empId, String status) { HrmLeaveReqBo bo = new HrmLeaveReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmTravelReqBo buildTravelBo(Long empId, String status) { HrmTravelReqBo bo = new HrmTravelReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmSealReqBo buildSealBo(Long empId, String status) { HrmSealReqBo bo = new HrmSealReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmReimburseReqBo buildReimburseBo(Long empId, String status) { HrmReimburseReqBo bo = new HrmReimburseReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmAppropriationReqBo buildAppropriationBo(Long empId, String status) { HrmAppropriationReqBo bo = new HrmAppropriationReqBo(); bo.setEmpId(empId); bo.setStatus(status); return bo; }
private HrmLeaveReqBo buildLeaveBo(Long empId) { HrmLeaveReqBo bo = new HrmLeaveReqBo(); bo.setEmpId(empId); return bo; }
private HrmTravelReqBo buildTravelBo(Long empId) { HrmTravelReqBo bo = new HrmTravelReqBo(); bo.setEmpId(empId); return bo; }
private HrmSealReqBo buildSealBo(Long empId) { HrmSealReqBo bo = new HrmSealReqBo(); bo.setEmpId(empId); return bo; }
private HrmReimburseReqBo buildReimburseBo(Long empId) { HrmReimburseReqBo bo = new HrmReimburseReqBo(); bo.setEmpId(empId); return bo; }
private HrmAppropriationReqBo buildAppropriationBo(Long empId) { HrmAppropriationReqBo bo = new HrmAppropriationReqBo(); bo.setEmpId(empId); return bo; }
private List<HrmMyApplyVo> mapLeave(List<HrmLeaveReqVo> list, String nickName) { return list.stream().map(v -> toVo("leave", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapTravel(List<HrmTravelReqVo> list, String nickName) { return list.stream().map(v -> toVo("travel", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapSeal(List<HrmSealReqVo> list, String nickName) { return list.stream().map(v -> toVo("seal", v.getBizId(), v.getEmpId(), nickName, v.getPurpose() != null ? v.getPurpose() : v.getRemark(), v.getStatus(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapReimburse(List<HrmReimburseReqVo> list, String nickName) { return list.stream().map(v -> toVo("reimburse", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapAppropriation(List<HrmAppropriationReqVo> list, String nickName) { return list.stream().map(v -> toVo("appropriation", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getStatus(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapLeave(List<HrmLeaveReqVo> list, String nickName) { return list.stream().map(v -> toVo("leave", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapTravel(List<HrmTravelReqVo> list, String nickName) { return list.stream().map(v -> toVo("travel", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapSeal(List<HrmSealReqVo> list, String nickName) { return list.stream().map(v -> toVo("seal", v.getBizId(), v.getEmpId(), nickName, v.getPurpose() != null ? v.getPurpose() : v.getRemark(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapReimburse(List<HrmReimburseReqVo> list, String nickName) { return list.stream().map(v -> toVo("reimburse", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getCreateTime(), v)).collect(Collectors.toList()); }
private List<HrmMyApplyVo> mapAppropriation(List<HrmAppropriationReqVo> list, String nickName) { return list.stream().map(v -> toVo("appropriation", v.getBizId(), v.getEmpId(), nickName, v.getReason(), v.getCreateTime(), v)).collect(Collectors.toList()); }
@SuppressWarnings("unchecked")
private HrmMyApplyVo toVo(String bizType, Long bizId, Long empId, String nickName, String title, String status, java.util.Date createTime, Object source) {
private HrmMyApplyVo toVo(String bizType, Long bizId, Long empId, String nickName, String title, java.util.Date createTime, Object source) {
HrmMyApplyVo vo = new HrmMyApplyVo();
vo.setBizType(bizType);
vo.setBizId(bizId);
vo.setEmpId(empId);
vo.setNickName(nickName);
vo.setTitle(title);
vo.setStatus(status);
vo.setCreateTime(createTime);
if (source != null) {
vo.setBizData(objectMapper.convertValue(source, Map.class));

View File

@@ -65,24 +65,6 @@ public class HrmSealReqController extends BaseController {
return toAjax(service.deleteWithValidByIds(java.util.Arrays.asList(bizIds), true));
}
@Log(title = "用印申请", businessType = BusinessType.UPDATE)
@PostMapping("/{bizId}/approve")
public R<Void> approve(@PathVariable @NotNull Long bizId) {
return toAjax(service.updateStatus(bizId, "approved"));
}
@Log(title = "用印申请", businessType = BusinessType.UPDATE)
@PostMapping("/{bizId}/reject")
public R<Void> reject(@PathVariable @NotNull Long bizId) {
return toAjax(service.updateStatus(bizId, "rejected"));
}
@Log(title = "用印申请", businessType = BusinessType.UPDATE)
@PostMapping("/{bizId}/cancel")
public R<Void> cancel(@PathVariable @NotNull Long bizId) {
return toAjax(service.updateStatus(bizId, "canceled"));
}
@Log(title = "用印盖章(Java)", businessType = BusinessType.UPDATE)
@PostMapping("/{bizId}/stamp/java")
public R<String> stampJava(@PathVariable @NotNull Long bizId, @Validated @RequestBody HrmSealStampBo bo) {

View File

@@ -45,9 +45,6 @@ public class HrmAppropriationReq extends BaseEntity {
/** 拨款事由 */
private String reason;
/** 状态 draft/pending/approved/rejected/canceled */
private String status;
/** 申请附件oss_id列表(CSV) */
private String accessoryApplyIds;

View File

@@ -25,7 +25,6 @@ public class HrmLeaveReq extends BaseEntity implements Serializable {
private Date endTime;
private java.math.BigDecimal hours;
private String reason;
private String status;
private String accessoryApplyIds;
private String accessoryReceiptIds;
private String remark;

View File

@@ -27,8 +27,6 @@ public class HrmReimburseReq extends BaseEntity {
private String reason;
private String status;
private String accessoryApplyIds;
private String accessoryReceiptIds;

View File

@@ -46,9 +46,6 @@ public class HrmSealReq extends BaseEntity {
/** 回执附件ID列表(CSV对应sys_oss或直接URL) */
private String receiptFileIds;
/** 状态 draft/running/approved/rejected/canceled */
private String status;
/** 备注 */
private String remark;

View File

@@ -24,7 +24,6 @@ public class HrmTravelReq extends BaseEntity {
private String travelType;
private String destination;
private String reason;
private String status;
private String accessoryApplyIds;
private String accessoryReceiptIds;
private String payeeName;

View File

@@ -44,9 +44,6 @@ public class HrmAppropriationReqBo extends BaseEntity {
/** 拨款事由 */
private String reason;
/** 状态 draft/pending/approved/rejected/canceled */
private String status;
/** 无模板时,自选审批人 userId */
private Long manualAssigneeUserId;

View File

@@ -35,7 +35,6 @@ public class HrmLeaveReqBo extends BaseEntity {
private java.math.BigDecimal hours;
private String reason;
private String status;
/**
* 流程模板ID前端选择模板流程时传入

View File

@@ -26,8 +26,6 @@ public class HrmReimburseReqBo extends BaseEntity {
private String reason;
private String status;
// 无模板时,自选审批人 userId
private Long manualAssigneeUserId;

View File

@@ -40,9 +40,6 @@ public class HrmSealReqBo extends BaseEntity {
/** 备注 */
private String remark;
/** 状态 draft/running/approved/rejected/canceled */
private String status;
/** 关联流程模板ID旧字段兼容历史前端/代码) */
private Long flowTplId;

View File

@@ -30,7 +30,6 @@ public class HrmTravelReqBo extends BaseEntity {
private String travelType;
private String destination;
private String reason;
private String status;
// 无模板时,自选审批人 userId
private Long manualAssigneeUserId;

View File

@@ -91,9 +91,6 @@ public class HrmAppropriationReqVo implements Serializable {
@Excel(name = "拨款事由")
private String reason;
@Excel(name = "状态")
private String status;
@Excel(name = "申请附件")
private String accessoryApplyIds;

View File

@@ -59,8 +59,6 @@ public class HrmLeaveReqVo implements Serializable {
private BigDecimal hours;
@Excel(name = "原因")
private String reason;
@Excel(name = "状态")
private String status;
@Excel(name = "申请附件")
private String accessoryApplyIds;
@Excel(name = "回执附件")

View File

@@ -79,9 +79,6 @@ public class HrmReimburseReqVo implements Serializable {
@Excel(name = "报销事由")
private String reason;
@Excel(name = "状态")
private String status;
@Excel(name = "报销单据附件")
private String accessoryApplyIds;

View File

@@ -91,9 +91,6 @@ public class HrmSealReqVo implements Serializable {
@Excel(name = "PDF页数")
private Integer pdfPageTotal;
@Excel(name = "状态")
private String status;
@Excel(name = "备注")
private String remark;

View File

@@ -58,8 +58,6 @@ public class HrmTravelReqVo implements Serializable {
private String destination;
@Excel(name = "原因")
private String reason;
@Excel(name = "状态")
private String status;
@Excel(name = "申请附件")
private String accessoryApplyIds;
@Excel(name = "回执附件")

View File

@@ -26,11 +26,6 @@ public interface IHrmAppropriationReqService {
Boolean updateByBo(HrmAppropriationReqBo bo);
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
*状态更新draft/running/approved/rejected/canceled
*/
Boolean updateStatus(Long bizId, String status);
}

View File

@@ -27,11 +27,6 @@ public interface IHrmSealReqService {
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
* 简单状态更新draft/running/approved/rejected/canceled
*/
Boolean updateStatus(Long bizId, String status);
/**
* Java 盖章,返回盖章后文件 URL
*/

View File

@@ -1,120 +0,0 @@
package com.ruoyi.hrm.service.impl;
import com.ruoyi.hrm.domain.HrmLeaveReq;
import com.ruoyi.hrm.domain.HrmReimburseReq;
import com.ruoyi.hrm.domain.HrmTravelReq;
import com.ruoyi.hrm.domain.HrmSealReq;
import com.ruoyi.hrm.domain.HrmAppropriationReq;
import com.ruoyi.hrm.mapper.HrmLeaveReqMapper;
import com.ruoyi.hrm.mapper.HrmReimburseReqMapper;
import com.ruoyi.hrm.mapper.HrmTravelReqMapper;
import com.ruoyi.hrm.mapper.HrmSealReqMapper;
import com.ruoyi.hrm.mapper.HrmAppropriationReqMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* 将流程结果同步到业务表状态。
* 业务表状态规范pending/approved/rejected
*/
@Component
@RequiredArgsConstructor
public class BizStatusSyncHelper {
private final HrmLeaveReqMapper leaveReqMapper;
private final HrmTravelReqMapper travelReqMapper;
private final HrmSealReqMapper sealReqMapper;
private final HrmReimburseReqMapper reimburseReqMapper;
private final HrmAppropriationReqMapper appropriationReqMapper;
public void setBizApproved(String bizType, Long bizId) {
if (bizType == null || bizId == null) return;
if ("leave".equalsIgnoreCase(bizType)) {
HrmLeaveReq u = new HrmLeaveReq();
u.setBizId(bizId);
u.setStatus("approved");
leaveReqMapper.updateById(u);
} else if ("travel".equalsIgnoreCase(bizType)) {
HrmTravelReq u = new HrmTravelReq();
u.setBizId(bizId);
u.setStatus("approved");
travelReqMapper.updateById(u);
} else if ("seal".equalsIgnoreCase(bizType)) {
HrmSealReq u = new HrmSealReq();
u.setBizId(bizId);
u.setStatus("approved");
sealReqMapper.updateById(u);
} else if ("reimburse".equalsIgnoreCase(bizType)) {
HrmReimburseReq u = new HrmReimburseReq();
u.setBizId(bizId);
u.setStatus("approved");
reimburseReqMapper.updateById(u);
} else if ("appropriation".equalsIgnoreCase(bizType)) {
HrmAppropriationReq u = new HrmAppropriationReq();
u.setBizId(bizId);
u.setStatus("approved");
appropriationReqMapper.updateById(u);
}
}
public void setBizPending(String bizType, Long bizId) {
if (bizType == null || bizId == null) return;
if ("leave".equalsIgnoreCase(bizType)) {
HrmLeaveReq u = new HrmLeaveReq();
u.setBizId(bizId);
u.setStatus("pending");
leaveReqMapper.updateById(u);
} else if ("travel".equalsIgnoreCase(bizType)) {
HrmTravelReq u = new HrmTravelReq();
u.setBizId(bizId);
u.setStatus("pending");
travelReqMapper.updateById(u);
} else if ("seal".equalsIgnoreCase(bizType)) {
HrmSealReq u = new HrmSealReq();
u.setBizId(bizId);
u.setStatus("pending");
sealReqMapper.updateById(u);
} else if ("reimburse".equalsIgnoreCase(bizType)) {
HrmReimburseReq u = new HrmReimburseReq();
u.setBizId(bizId);
u.setStatus("pending");
reimburseReqMapper.updateById(u);
} else if ("appropriation".equalsIgnoreCase(bizType)) {
HrmAppropriationReq u = new HrmAppropriationReq();
u.setBizId(bizId);
u.setStatus("pending");
appropriationReqMapper.updateById(u);
}
}
public void setBizRejected(String bizType, Long bizId) {
if (bizType == null || bizId == null) return;
if ("leave".equalsIgnoreCase(bizType)) {
HrmLeaveReq u = new HrmLeaveReq();
u.setBizId(bizId);
u.setStatus("rejected");
leaveReqMapper.updateById(u);
} else if ("travel".equalsIgnoreCase(bizType)) {
HrmTravelReq u = new HrmTravelReq();
u.setBizId(bizId);
u.setStatus("rejected");
travelReqMapper.updateById(u);
} else if ("seal".equalsIgnoreCase(bizType)) {
HrmSealReq u = new HrmSealReq();
u.setBizId(bizId);
u.setStatus("rejected");
sealReqMapper.updateById(u);
} else if ("reimburse".equalsIgnoreCase(bizType)) {
HrmReimburseReq u = new HrmReimburseReq();
u.setBizId(bizId);
u.setStatus("rejected");
reimburseReqMapper.updateById(u);
} else if ("appropriation".equalsIgnoreCase(bizType)) {
HrmAppropriationReq u = new HrmAppropriationReq();
u.setBizId(bizId);
u.setStatus("rejected");
appropriationReqMapper.updateById(u);
}
}
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.hrm.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
@@ -71,7 +70,6 @@ public class HrmAppropriationReqServiceImpl implements IHrmAppropriationReqServi
@Transactional(rollbackFor = Exception.class)
public HrmAppropriationReqVo insertByBo(HrmAppropriationReqBo bo) {
HrmAppropriationReq add = BeanUtil.toBean(bo, HrmAppropriationReq.class);
add.setStatus(defaultStatus(add.getStatus()));
boolean ok = baseMapper.insert(add) > 0;
HrmAppropriationReqVo bean = BeanUtil.toBean(add, HrmAppropriationReqVo.class);
@@ -81,7 +79,7 @@ public class HrmAppropriationReqServiceImpl implements IHrmAppropriationReqServi
saveInvoiceItems("appropriation", add.getBizId(), bo.getInvoiceItems());
}
if (ok && "pending".equalsIgnoreCase(add.getStatus())) {
if (ok) {
// 获取流程启动人ID
Long startUserId = LoginHelper.getUserId();
@@ -137,15 +135,6 @@ public class HrmAppropriationReqServiceImpl implements IHrmAppropriationReqServi
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateStatus(Long bizId, String status) {
HrmAppropriationReq req = new HrmAppropriationReq();
req.setBizId(bizId);
req.setStatus(status);
return baseMapper.updateById(req) > 0;
}
private void saveInvoiceItems(String bizType, Long bizId, List<HrmInvoiceItemBo> boList) {
invoiceItemMapper.delete(Wrappers.<HrmInvoiceItem>lambdaQuery()
.eq(HrmInvoiceItem::getBizType, bizType)
@@ -163,20 +152,5 @@ public class HrmAppropriationReqServiceImpl implements IHrmAppropriationReqServi
invoiceItemMapper.insert(item);
}
}
@SuppressWarnings("unused")
private LambdaQueryWrapper<HrmAppropriationReq> buildQueryWrapper(HrmAppropriationReqBo bo) {
LambdaQueryWrapper<HrmAppropriationReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmAppropriationReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmAppropriationReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmAppropriationReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getAppropriationType() != null, HrmAppropriationReq::getAppropriationType, bo.getAppropriationType());
lqw.eq(bo.getStatus() != null, HrmAppropriationReq::getStatus, bo.getStatus());
return lqw;
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
}

View File

@@ -40,7 +40,6 @@ public class HrmFlowTaskServiceImpl implements IHrmFlowTaskService {
private final IHrmSealReqService sealReqService;
private final IHrmFlowCcService ccService;
private final FlowAssigneeHelper assigneeHelper;
private final BizStatusSyncHelper bizStatusSyncHelper;
// 注入五个业务Mapper
private final HrmLeaveReqMapper leaveReqMapper;
@@ -199,16 +198,12 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
inst.setStatus("approved");
inst.setCurrentNodeId(null);
instanceMapper.updateById(inst);
// 若业务为用印,更新用印状态为已批准,并执行盖章
if ("seal".equalsIgnoreCase(inst.getBizType())) {
sealReqService.updateStatus(inst.getBizId(), "approved");
if (stampBo != null) {
// 盖章动作也写入流转历史
saveAction(taskId, inst.getInstId(), task.getBizType(), task.getBizId(), task.getAssigneeUserId(), "stamp", "盖章", operatorUserId);
sealReqService.stampWithJava(inst.getBizId(), stampBo);
}
// 若业务为用印,执行盖章(状态由 hrm_flow_instance 统一维护,不再回写业务表)
if ("seal".equalsIgnoreCase(inst.getBizType()) && stampBo != null) {
// 盖章动作也写入流转历史
saveAction(taskId, inst.getInstId(), task.getBizType(), task.getBizId(), task.getAssigneeUserId(), "stamp", "盖章", operatorUserId);
sealReqService.stampWithJava(inst.getBizId(), stampBo);
}
bizStatusSyncHelper.setBizApproved(inst.getBizType(), inst.getBizId());
return true;
}
@@ -279,14 +274,10 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
inst.setStatus("approved");
inst.setCurrentNodeId(null);
instanceMapper.updateById(inst);
// 若业务为用印,更新用印状态为已批准
if ("seal".equalsIgnoreCase(inst.getBizType())) {
sealReqService.updateStatus(inst.getBizId(), "approved");
if (stampBo != null) {
sealReqService.stampWithJava(inst.getBizId(), stampBo);
}
// 若业务为用印且传入盖章参数,执行盖章
if ("seal".equalsIgnoreCase(inst.getBizType()) && stampBo != null) {
sealReqService.stampWithJava(inst.getBizId(), stampBo);
}
bizStatusSyncHelper.setBizApproved(inst.getBizType(), inst.getBizId());
}
return true;
}
@@ -309,10 +300,6 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
inst.setStatus("rejected");
inst.setCurrentNodeId(null);
instanceMapper.updateById(inst);
if ("seal".equalsIgnoreCase(inst.getBizType())) {
sealReqService.updateStatus(inst.getBizId(), "rejected");
}
bizStatusSyncHelper.setBizRejected(inst.getBizType(), inst.getBizId());
return true;
}
@@ -346,7 +333,6 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
reTask.setStatus("pending");
baseMapper.insert(reTask);
bizStatusSyncHelper.setBizPending(inst.getBizType(), inst.getBizId());
return true;
}
@@ -359,9 +345,6 @@ private void fillBizData(List<HrmFlowTaskVo> tasks) {
reTask.setAssigneeUserId(actionUserId != null ? actionUserId : task.getAssigneeUserId());
reTask.setStatus("pending");
baseMapper.insert(reTask);
if ("seal".equalsIgnoreCase(inst.getBizType())) {
sealReqService.updateStatus(inst.getBizId(), "running");
}
return true;
}

View File

@@ -1,7 +1,6 @@
package com.ruoyi.hrm.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
@@ -65,12 +64,11 @@ public class HrmLeaveReqServiceImpl implements IHrmLeaveReqService {
@Transactional(rollbackFor = Exception.class)
public HrmLeaveReqVo insertByBo(HrmLeaveReqBo bo) {
HrmLeaveReq add = BeanUtil.toBean(bo, HrmLeaveReq.class);
add.setStatus(defaultStatus(add.getStatus()));
boolean ok = baseMapper.insert(add) > 0;
HrmLeaveReqVo bean = BeanUtil.toBean(add, HrmLeaveReqVo.class);
// 当提交为 pending 时,自动启动流程实例hrm_flow_instance/hrm_flow_task
if (ok && "pending".equalsIgnoreCase(add.getStatus())) {
// 插入成功后自动启动流程实例hrm_flow_instance/hrm_flow_task,状态由 flow_instance 唯一维护
if (ok) {
Long startUserId = LoginHelper.getUserId();
@@ -173,18 +171,4 @@ public class HrmLeaveReqServiceImpl implements IHrmLeaveReqService {
return stats;
}
private LambdaQueryWrapper<HrmLeaveReq> buildQueryWrapper(HrmLeaveReqBo bo) {
LambdaQueryWrapper<HrmLeaveReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmLeaveReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmLeaveReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmLeaveReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getLeaveType() != null, HrmLeaveReq::getLeaveType, bo.getLeaveType());
lqw.eq(bo.getStatus() != null, HrmLeaveReq::getStatus, bo.getStatus());
lqw.eq(bo.getStartTime() != null, HrmLeaveReq::getStartTime, bo.getStartTime());
return lqw;
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
}

View File

@@ -2,7 +2,6 @@ package com.ruoyi.hrm.service.impl;
import com.ruoyi.common.helper.LoginHelper;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
@@ -68,7 +67,6 @@ public class HrmReimburseReqServiceImpl implements IHrmReimburseReqService {
@Transactional(rollbackFor = Exception.class)
public HrmReimburseReqVo insertByBo(HrmReimburseReqBo bo) {
HrmReimburseReq add = BeanUtil.toBean(bo, HrmReimburseReq.class);
add.setStatus(defaultStatus(add.getStatus()));
boolean ok = baseMapper.insert(add) > 0;
HrmReimburseReqVo bean = BeanUtil.toBean(add, HrmReimburseReqVo.class);
@@ -78,7 +76,7 @@ public class HrmReimburseReqServiceImpl implements IHrmReimburseReqService {
saveInvoiceItems("reimburse", add.getBizId(), bo.getInvoiceItems());
}
if (ok && "pending".equalsIgnoreCase(add.getStatus())) {
if (ok) {
Long startUserId = LoginHelper.getUserId();
HrmFlowTemplate tpl = null;
@@ -135,16 +133,6 @@ public class HrmReimburseReqServiceImpl implements IHrmReimburseReqService {
}
private LambdaQueryWrapper<HrmReimburseReq> buildQueryWrapper(HrmReimburseReqBo bo) {
LambdaQueryWrapper<HrmReimburseReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmReimburseReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmReimburseReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmReimburseReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getReimburseType() != null, HrmReimburseReq::getReimburseType, bo.getReimburseType());
lqw.eq(bo.getStatus() != null, HrmReimburseReq::getStatus, bo.getStatus());
return lqw;
}
private void saveInvoiceItems(String bizType, Long bizId, List<HrmInvoiceItemBo> boList) {
// 先清除旧数据,再插入新数据(更新场景兼容)
invoiceItemMapper.delete(Wrappers.<HrmInvoiceItem>lambdaQuery()
@@ -163,9 +151,5 @@ public class HrmReimburseReqServiceImpl implements IHrmReimburseReqService {
invoiceItemMapper.insert(item);
}
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
}

View File

@@ -2,8 +2,6 @@ package com.ruoyi.hrm.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
@@ -128,7 +126,6 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
@Transactional(rollbackFor = Exception.class)
public HrmSealReqVo insertByBo(HrmSealReqBo bo) {
HrmSealReq add = BeanUtil.toBean(bo, HrmSealReq.class);
add.setStatus(defaultStatus(add.getStatus()));
validEntityBeforeSave(add);
boolean ok = baseMapper.insert(add) > 0;
@@ -144,7 +141,6 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
start.setContentJson(bo.getContentJson());
Long instId = flowInstanceService.startInstance(start);
updateStatus(add.getBizId(), "running");
bean.setInstId(instId);
}
return bean;
@@ -169,15 +165,6 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public Boolean updateStatus(Long bizId, String status) {
HrmSealReq req = new HrmSealReq();
req.setBizId(bizId);
req.setStatus(status);
return baseMapper.updateById(req) > 0;
}
@Override
@Transactional(rollbackFor = Exception.class)
public String stampWithJava(Long bizId, HrmSealStampBo cmd) {
@@ -203,25 +190,10 @@ public class HrmSealReqServiceImpl implements IHrmSealReqService {
throw new ServiceException("Python盖章接口未实现");
}
private LambdaQueryWrapper<HrmSealReq> buildQueryWrapper(HrmSealReqBo bo) {
LambdaQueryWrapper<HrmSealReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmSealReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmSealReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmSealReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getSealType() != null, HrmSealReq::getSealType, bo.getSealType());
lqw.eq(bo.getStatus() != null, HrmSealReq::getStatus, bo.getStatus());
lqw.orderByDesc(HrmSealReq::getCreateTime);
return lqw;
}
private void validEntityBeforeSave(HrmSealReq entity) {
// 预留数据校验,如唯一约束
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
private String doPdfStamp(HrmSealStampBo cmd) {
try (InputStream pdfIn = getObject(cmd.getTargetFileUrl());
InputStream imgIn = getObject(cmd.getStampImageUrl());

View File

@@ -1,17 +1,18 @@
package com.ruoyi.hrm.service.impl;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.hrm.domain.HrmFlowInstance;
import com.ruoyi.hrm.domain.HrmFlowTemplate;
import com.ruoyi.hrm.domain.HrmTravelReq;
import com.ruoyi.hrm.domain.bo.HrmFlowStartBo;
import com.ruoyi.hrm.domain.bo.HrmTravelReqBo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.hrm.domain.vo.HrmTravelReqVo;
import com.ruoyi.hrm.mapper.HrmFlowInstanceMapper;
import com.ruoyi.hrm.mapper.HrmFlowTemplateMapper;
import com.ruoyi.hrm.mapper.HrmTravelReqMapper;
import com.ruoyi.hrm.service.IHrmFlowInstanceService;
@@ -31,6 +32,7 @@ public class HrmTravelReqServiceImpl implements IHrmTravelReqService {
private final HrmTravelReqMapper baseMapper;
private final HrmFlowTemplateMapper flowTemplateMapper;
private final IHrmFlowInstanceService flowInstanceService;
private final HrmFlowInstanceMapper flowInstanceMapper;
@Override
public HrmTravelReqVo queryById(Long bizId) {
@@ -58,15 +60,12 @@ public class HrmTravelReqServiceImpl implements IHrmTravelReqService {
@Transactional(rollbackFor = Exception.class)
public HrmTravelReqVo insertByBo(HrmTravelReqBo bo) {
HrmTravelReq add = BeanUtil.toBean(bo, HrmTravelReq.class);
add.setStatus(defaultStatus(add.getStatus()));
boolean ok = baseMapper.insert(add) > 0;
HrmTravelReqVo bean = BeanUtil.toBean(add, HrmTravelReqVo.class);
// 业务表状态规范pending/approved/rejected
// 当提交为 pending 时自动启动流程实例hrm_flow_instance/hrm_flow_task
// 1) 优先前端明确选择了模板tplId 不为空)
// 插入成功后自动启动流程实例hrm_flow_instance/hrm_flow_task状态由 flow_instance 唯一维护
HrmFlowTemplate tpl = null;
if (ok && "pending".equalsIgnoreCase(add.getStatus())) {
if (ok) {
if(bo.getTplId() != null){
// 选择启用的最高版本模板(允许无模板:走自选审批人一次性审批)
tpl = flowTemplateMapper.selectOne(Wrappers.<HrmFlowTemplate>lambdaQuery()
@@ -116,20 +115,6 @@ public class HrmTravelReqServiceImpl implements IHrmTravelReqService {
return baseMapper.deleteBatchIds(ids) > 0;
}
private LambdaQueryWrapper<HrmTravelReq> buildQueryWrapper(HrmTravelReqBo bo) {
LambdaQueryWrapper<HrmTravelReq> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getBizId() != null, HrmTravelReq::getBizId, bo.getBizId());
lqw.eq(bo.getEmpId() != null, HrmTravelReq::getEmpId, bo.getEmpId());
lqw.eq(bo.getProjectId() != null, HrmTravelReq::getProjectId, bo.getProjectId());
lqw.eq(bo.getStatus() != null, HrmTravelReq::getStatus, bo.getStatus());
lqw.eq(bo.getStartTime() != null, HrmTravelReq::getStartTime, bo.getStartTime());
return lqw;
}
private String defaultStatus(String status) {
return status == null ? "draft" : status;
}
@Override
@Transactional(rollbackFor = Exception.class)
public int earlyEnd(Long bizId) {
@@ -138,22 +123,23 @@ public class HrmTravelReqServiceImpl implements IHrmTravelReqService {
throw new RuntimeException("出差申请不存在");
}
String status = travelReq.getStatus();
if (!"approved".equals(status) && !"in_progress".equals(status)) {
throw new RuntimeException("当前状态不能提前结束,只有已通过或进行中的出差才能提前结束");
// 出差是否已通过,改由流程实例判定
HrmFlowInstance inst = flowInstanceMapper.selectOne(Wrappers.<HrmFlowInstance>lambdaQuery()
.eq(HrmFlowInstance::getBizType, "travel")
.eq(HrmFlowInstance::getBizId, bizId)
.orderByDesc(HrmFlowInstance::getInstId)
.last("limit 1"));
if (inst == null || !"approved".equalsIgnoreCase(inst.getStatus())) {
throw new RuntimeException("当前状态不能提前结束,只有已通过的出差才能提前结束");
}
// 3. 检查是否已经提前结束过
if (travelReq.getActualEndTime() != null) {
throw new RuntimeException("该出差已经提前结束过了");
}
// 4. 更新实际结束时间为当前时间
// 更新实际结束时间为当前时间;「已完成」由 actualEndTime 判定,无需单独回写状态
travelReq.setActualEndTime(new Date());
// 5. 可选:更新状态为已完成
travelReq.setStatus("completed");
// 6. 执行更新
int result = baseMapper.updateById(travelReq);
if (result <= 0) {
throw new RuntimeException("提前结束失败");

View File

@@ -11,7 +11,6 @@
<result column="bank_name" property="bankName"/>
<result column="bank_account" property="bankAccount"/>
<result column="reason" property="reason"/>
<result column="status" property="status"/>
<result column="accessory_apply_ids" property="accessoryApplyIds"/>
<result column="accessory_receipt_ids" property="accessoryReceiptIds"/>
<result column="remark" property="remark"/>
@@ -99,9 +98,6 @@
<if test="bo.appropriationType != null and bo.appropriationType != ''">
AND a.appropriation_type = #{bo.appropriationType}
</if>
<if test="bo.status != null and bo.status != ''">
AND a.status = #{bo.status}
</if>
ORDER BY a.create_time DESC
</select>
@@ -139,9 +135,6 @@
<if test="bo.appropriationType != null and bo.appropriationType != ''">
AND a.appropriation_type = #{bo.appropriationType}
</if>
<if test="bo.status != null and bo.status != ''">
AND a.status = #{bo.status}
</if>
ORDER BY a.create_time DESC
</select>
</mapper>

View File

@@ -10,7 +10,6 @@
<result column="end_time" property="endTime"/>
<result column="hours" property="hours"/>
<result column="reason" property="reason"/>
<result column="status" property="status"/>
<result column="accessory_apply_ids" property="accessoryApplyIds"/>
<result column="accessory_receipt_ids" property="accessoryReceiptIds"/>
<result column="remark" property="remark"/>
@@ -98,9 +97,6 @@
<if test="bo.leaveType != null and bo.leaveType != ''">
AND l.leave_type = #{bo.leaveType}
</if>
<if test="bo.status != null and bo.status != ''">
AND l.status = #{bo.status}
</if>
<if test="bo.startTime != null">
AND l.start_time = #{bo.startTime}
</if>
@@ -141,9 +137,6 @@
<if test="bo.leaveType != null and bo.leaveType != ''">
AND l.leave_type = #{bo.leaveType}
</if>
<if test="bo.status != null and bo.status != ''">
AND l.status = #{bo.status}
</if>
<if test="bo.startTime != null">
AND l.start_time = #{bo.startTime}
</if>
@@ -154,20 +147,22 @@
SELECT
COUNT(*) as totalRequests,
SUM(hours) as totalHours
FROM hrm_leave_req
WHERE del_flag = 0
AND status = 'approved'
FROM hrm_leave_req l
WHERE l.del_flag = 0
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
</select>
<select id="selectLeaveByType" resultType="java.util.Map">
SELECT
leave_type as leaveType,
l.leave_type as leaveType,
COUNT(*) as count,
SUM(hours) as totalHours
FROM hrm_leave_req
WHERE del_flag = 0
AND status = 'approved'
GROUP BY leave_type
SUM(l.hours) as totalHours
FROM hrm_leave_req l
WHERE l.del_flag = 0
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
GROUP BY l.leave_type
ORDER BY totalHours DESC
</select>
@@ -180,21 +175,23 @@
JOIN hrm_employee e ON l.emp_id = e.emp_id AND e.del_flag = 0
LEFT JOIN sys_dept d ON e.dept_id = d.dept_id AND d.del_flag = '0'
WHERE l.del_flag = 0
AND l.status = 'approved'
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
GROUP BY d.dept_id, d.dept_name
ORDER BY totalHours DESC
</select>
<select id="selectLeaveByMonth" resultType="java.util.Map">
SELECT
DATE_FORMAT(start_time, '%Y-%m') as month,
DATE_FORMAT(l.start_time, '%Y-%m') as month,
COUNT(*) as count,
SUM(hours) as totalHours
FROM hrm_leave_req
WHERE del_flag = 0
AND status = 'approved'
AND YEAR(start_time) = #{year}
GROUP BY DATE_FORMAT(start_time, '%Y-%m')
SUM(l.hours) as totalHours
FROM hrm_leave_req l
WHERE l.del_flag = 0
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
AND YEAR(l.start_time) = #{year}
GROUP BY DATE_FORMAT(l.start_time, '%Y-%m')
ORDER BY month
</select>
@@ -206,7 +203,8 @@
SELECT COUNT(DISTINCT l.emp_id)
FROM hrm_leave_req l
WHERE l.del_flag = 0
AND l.status = 'approved'
AND EXISTS (SELECT 1 FROM hrm_flow_instance fi
WHERE fi.biz_type = 'leave' AND fi.biz_id = l.biz_id AND fi.status = 'approved')
AND NOW() BETWEEN l.start_time AND l.end_time
</select>
</mapper>

View File

@@ -8,7 +8,6 @@
<result column="reimburse_type" property="reimburseType"/>
<result column="total_amount" property="totalAmount"/>
<result column="reason" property="reason"/>
<result column="status" property="status"/>
<result column="accessory_apply_ids" property="accessoryApplyIds"/>
<result column="accessory_receipt_ids" property="accessoryReceiptIds"/>
<result column="remark" property="remark"/>
@@ -96,9 +95,6 @@
<if test="bo.reimburseType != null and bo.reimburseType != ''">
AND r.reimburse_type = #{bo.reimburseType}
</if>
<if test="bo.status != null and bo.status != ''">
AND r.status = #{bo.status}
</if>
ORDER BY r.create_time DESC
</select>
@@ -136,9 +132,6 @@
<if test="bo.reimburseType != null and bo.reimburseType != ''">
AND r.reimburse_type = #{bo.reimburseType}
</if>
<if test="bo.status != null and bo.status != ''">
AND r.status = #{bo.status}
</if>
ORDER BY r.create_time DESC
</select>
</mapper>

View File

@@ -11,7 +11,6 @@
<result column="receipt_required" property="receiptRequired"/>
<result column="receipt_status" property="receiptStatus"/>
<result column="receipt_file_ids" property="receiptFileIds"/>
<result column="status" property="status"/>
<result column="remark" property="remark"/>
<result column="create_by" property="createBy"/>
<result column="create_time" property="createTime"/>
@@ -100,9 +99,6 @@
<if test="bo.sealType != null and bo.sealType != ''">
AND s.seal_type = #{bo.sealType}
</if>
<if test="bo.status != null and bo.status != ''">
AND s.status = #{bo.status}
</if>
ORDER BY s.create_time DESC
</select>
@@ -140,9 +136,6 @@
<if test="bo.sealType != null and bo.sealType != ''">
AND s.seal_type = #{bo.sealType}
</if>
<if test="bo.status != null and bo.status != ''">
AND s.status = #{bo.status}
</if>
ORDER BY s.create_time DESC
</select>
</mapper>

View File

@@ -10,7 +10,6 @@
<result column="travel_type" property="travelType"/>
<result column="destination" property="destination"/>
<result column="reason" property="reason"/>
<result column="status" property="status"/>
<result column="accessory_apply_ids" property="accessoryApplyIds"/>
<result column="accessory_receipt_ids" property="accessoryReceiptIds"/>
<result column="payee_name" property="payeeName"/>
@@ -99,9 +98,6 @@
<if test="bo.projectId != null">
AND t.project_id = #{bo.projectId}
</if>
<if test="bo.status != null and bo.status != ''">
AND t.status = #{bo.status}
</if>
<if test="bo.startTime != null">
AND t.start_time = #{bo.startTime}
</if>
@@ -139,9 +135,6 @@
<if test="bo.projectId != null">
AND t.project_id = #{bo.projectId}
</if>
<if test="bo.status != null and bo.status != ''">
AND t.status = #{bo.status}
</if>
<if test="bo.startTime != null">
AND t.start_time = #{bo.startTime}
</if>