feat(bpm): 实现补卡申请功能

- 新增补卡申请 API 接口和实现类
- 添加补卡申请创建、审核等服务方法
- 实现补卡申请结果监听器
- 新增补卡申请相关 VO 类
- 集成 Redis缓存补卡次数
-调用考勤 API 进行补卡操作
This commit is contained in:
furongxin 2024-11-12 21:23:48 +08:00
parent 83d3fdb323
commit c897545148
8 changed files with 178 additions and 16 deletions

View File

@ -0,0 +1,41 @@
package cn.iocoder.yudao.module.bpm.api.oa;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.replacementCard.ReplacementCardItemVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReplacementCardDO;
import cn.iocoder.yudao.module.bpm.service.oa.BpmOAReplacementCardService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
@RestController
@Validated
public class BpmOAReplacementCardApiImpl implements BpmOAReplacementCardApi{
@Resource
private BpmOAReplacementCardService replacementCardService;
@Override
public CommonResult<List<Long>> getPunchRecordIds() {
List<BpmOAReplacementCardDO> list = replacementCardService.getListByResult();
List<Long> punchRecordIds = new ArrayList<>();
for (BpmOAReplacementCardDO item : list) {
List<ReplacementCardItemVO> respVO = item.getApplicationItem();
//直接从数据库取出来的List<Reimbursement> 实际上是List<LinkedHashMap>类型 所以不能直接遍历
//将list再次转为json串然后由json串再转为list
String json = JsonUtils.toJsonString(respVO);
respVO = JsonUtils.parseArray(json, ReplacementCardItemVO.class);
punchRecordIds.addAll(convertList(respVO, ReplacementCardItemVO::getPunchRecordId));
}
return success(punchRecordIds);
}
}

View File

@ -14,7 +14,7 @@ import java.util.List;
*
* @author 符溶馨
*/
@Schema(description = "管理后台 - 薪资付款申请创建 Request VO")
@Schema(description = "管理后台 - 补卡申请创建 Request VO")
@Data
@EqualsAndHashCode()
@ToString(callSuper = true)

View File

@ -3,14 +3,21 @@ package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.replacementCard;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDate;
@Schema(description = "管理后台 - 补卡明细 Response VO")
@Data
public class ReplacementCardItemVO {
@Schema(description = "补卡日期")
private LocalDate date;
@Schema(description = "用卡缺卡记录编号")
private Long punchRecordId;
@Schema(description = "缺卡日期")
private String dayTime;
@Schema(description = "上下班类型 0上班 1下班")
private Integer workType;
@Schema(description = "打卡状态 0正常 1迟到 2早退 3缺卡 4未打卡(还没到打卡时间) 5补卡")
private Integer status;
@Schema(description = "补卡事由")
private String reason;

View File

@ -0,0 +1,15 @@
package cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.replacementCard;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
@Schema(description = "本月补卡申请 VO")
@Data
public class ReplacementCardRecord {
@Schema(description = "缺卡日期")
private String dayTime;
@Schema(description = "上下班类型 0上班 1下班")
private Integer workType;
}

View File

@ -11,6 +11,7 @@ import cn.iocoder.yudao.module.system.api.dept.DeptApi;
import cn.iocoder.yudao.module.system.api.dept.PostApi;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.equipment.UsersExtApi;
import cn.iocoder.yudao.module.system.api.group.AttendanceGroupApi;
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;
@ -25,7 +26,7 @@ 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
AssetsTypeApi.class, AssetReceiveApi.class, AttendanceApi.class, AttendanceGroupApi.class
})
public class RpcConfiguration {
}

View File

@ -4,6 +4,7 @@ import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.replacementCard.BpmOAR
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReplacementCardDO;
import javax.validation.Valid;
import java.util.List;
/**
* 补卡申请 Service 接口
@ -27,7 +28,7 @@ public interface BpmOAReplacementCardService {
* @param id 编号
* @param result 结果
*/
void updateReplacementCardResult(Long id, Integer result);
void updateReplacementCardResult(String processInstanceId, Long id, Integer result);
/**
* 获得补卡申请
@ -43,4 +44,10 @@ public interface BpmOAReplacementCardService {
* @return 补卡申请
*/
BpmOAReplacementCardDO getByProcessInstanceId(String processInstanceId);
/**
* 处理中的补卡申请
* @return 补卡申请列表
*/
List<BpmOAReplacementCardDO> getListByResult();
}

View File

@ -1,24 +1,40 @@
package cn.iocoder.yudao.module.bpm.service.oa;
import cn.iocoder.yudao.framework.common.Constants;
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.module.bpm.api.task.BpmProcessInstanceApi;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.bpm.api.task.dto.BpmProcessInstanceCreateReqDTO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.replacementCard.BpmOAReplacementCardCreateReqVO;
import cn.iocoder.yudao.module.bpm.controller.admin.oa.vo.replacementCard.ReplacementCardItemVO;
import cn.iocoder.yudao.module.bpm.dal.dataobject.oa.BpmOAReplacementCardDO;
import cn.iocoder.yudao.module.bpm.dal.mysql.oa.BpmOAReplacementCardMapper;
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.attendance.AttendanceApi;
import cn.iocoder.yudao.module.system.api.group.AttendanceGroupApi;
import com.alibaba.nacos.common.utils.StringUtils;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
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.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.bpm.enums.ErrorCodeConstants.OA_REPLACEMENT_CARD_NOT_EXISTS;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.INSUFFICIENT_NUMBER_OF_CARD_REFILLS;
/**
* OA 补卡申请 Service 实现类
@ -38,11 +54,20 @@ public class BpmOAReplacementCardServiceImpl extends BpmOABaseService implements
private BpmOAReplacementCardMapper replacementCardMapper;
@Resource
private BpmProcessInstanceApi processInstanceApi;
private BpmProcessInstanceService bpmProcessInstanceService;
@Resource
private BpmHistoryProcessInstanceService historyProcessInstanceService;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private AttendanceGroupApi attendanceGroupApi;
@Resource
private AttendanceApi attendanceApi;
@Override
public Long createReplacementCard(Long userId, BpmOAReplacementCardCreateReqVO createReqVO) {
@ -54,9 +79,9 @@ public class BpmOAReplacementCardServiceImpl extends BpmOABaseService implements
// 发起 BPM 流程
Map<String, Object> processInstanceVariables = new HashMap<>();
String processInstanceId = processInstanceApi.createProcessInstance(userId,
String processInstanceId = bpmProcessInstanceService.createProcessInstance(userId,
new BpmProcessInstanceCreateReqDTO().setProcessDefinitionKey(PROCESS_KEY)
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(replacementCard.getId()))).getCheckedData();
.setVariables(processInstanceVariables).setBusinessKey(String.valueOf(replacementCard.getId())));
// 将工作流的编号更新到 OA 补卡申请单中
replacementCardMapper.updateById(new BpmOAReplacementCardDO().setId(replacementCard.getId()).setProcessInstanceId(processInstanceId));
@ -72,19 +97,76 @@ public class BpmOAReplacementCardServiceImpl extends BpmOABaseService implements
if (fileItems != null && !fileItems.isEmpty()) {
uploadBpmFileProcessInstanceId(processInstanceId,fileItems) ;
}
// 发起补卡申请后 先扣除用户补卡次数
String key = "ReplacementCardNum" + "_" + userId + "_" + LocalDateTime.now().format(Constants.YEAR_MONTH_FORMAT);
String value = stringRedisTemplate.opsForValue().get(key);
if (StringUtils.isNotEmpty(value)) {
if (Integer.parseInt(value) > 0) {
stringRedisTemplate.opsForValue().increment(key, -(createReqVO.getApplicationItem().size()));
} else {
throw exception(INSUFFICIENT_NUMBER_OF_CARD_REFILLS);
}
}else {
// 如果redis不存在则从数据库获取
Integer num = attendanceGroupApi.getReplacementCardNum(userId).getCheckedData();
if (num > 0) {
num = num - createReqVO.getApplicationItem().size();
stringRedisTemplate.opsForValue().set(key, num.toString(), 32, TimeUnit.DAYS);
} else {
throw exception(INSUFFICIENT_NUMBER_OF_CARD_REFILLS);
}
}
return replacementCard.getId();
}
@Override
public void updateReplacementCardResult(Long id, Integer result) {
validateLeaveExists(id);
@Transactional(rollbackFor = Exception.class)
public void updateReplacementCardResult(String processInstanceId, Long id, Integer result) {
BpmOAReplacementCardDO replacementCard = validateLeaveExists(id);
replacementCardMapper.updateById(new BpmOAReplacementCardDO().setId(id).setResult(result));
//审核通过 最后节点
if (BpmProcessInstanceResultEnum.APPROVE.getResult().equals(result)) {
ProcessInstance instance = bpmProcessInstanceService.getProcessInstance(processInstanceId);
if (instance.isEnded()) {
List<ReplacementCardItemVO> respVO = replacementCard.getApplicationItem();
//直接从数据库取出来的List<Reimbursement> 实际上是List<LinkedHashMap>类型 所以不能直接遍历
//将list再次转为json串然后由json串再转为list
String json = JsonUtils.toJsonString(respVO);
respVO = JsonUtils.parseArray(json, ReplacementCardItemVO.class);
// 获取需补卡的打卡记录编号
List<Long> punchRecordIds = convertList(respVO, ReplacementCardItemVO::getPunchRecordId);
// 审核通过 则进行批量补卡操作
attendanceApi.replacementCard(punchRecordIds);
}
}
// -- 自己取消
// -- 审核拒绝
if (BpmProcessInstanceResultEnum.REJECT.getResult().equals(result)
|| BpmProcessInstanceResultEnum.CANCEL.getResult().equals(result)
|| BpmProcessInstanceResultEnum.BACK.getResult().equals(result)) {
// 恢复redis 中的补卡次数
String key = "ReplacementCardNum" + "_" + replacementCard.getUserId() + "_" + LocalDateTime.now().format(Constants.YEAR_MONTH_FORMAT);
stringRedisTemplate.opsForValue().increment(key, replacementCard.getApplicationItem().size());
}
}
private void validateLeaveExists(Long id) {
if (replacementCardMapper.selectById(id) == null) {
private BpmOAReplacementCardDO validateLeaveExists(Long id) {
BpmOAReplacementCardDO replacementCard = replacementCardMapper.selectById(id);
if (replacementCard == null) {
throw exception(OA_REPLACEMENT_CARD_NOT_EXISTS);
}
return replacementCard;
}
@Override
@ -98,4 +180,13 @@ public class BpmOAReplacementCardServiceImpl extends BpmOABaseService implements
return replacementCardMapper.selectOne(BpmOAReplacementCardDO::getProcessInstanceId, processInstanceId);
}
@Override
public List<BpmOAReplacementCardDO> getListByResult() {
return replacementCardMapper.selectList(new LambdaQueryWrapperX<BpmOAReplacementCardDO>()
.eq(BpmOAReplacementCardDO::getUserId, getLoginUserId())
.eq(BpmOAReplacementCardDO::getResult, BpmProcessInstanceResultEnum.PROCESS.getResult())
.like(BpmOAReplacementCardDO::getCreateTime, LocalDate.now().format(Constants.YEAR_MONTH_FORMAT)));
}
}

View File

@ -27,6 +27,6 @@ public class BpmOAReplacementCardResultListener extends BpmProcessInstanceResult
@Override
protected void onEvent(BpmProcessInstanceResultEvent event) {
ReplacementCardService.updateReplacementCardResult(Long.parseLong(event.getBusinessKey()), event.getResult());
ReplacementCardService.updateReplacementCardResult(event.getId(), Long.parseLong(event.getBusinessKey()), event.getResult());
}
}