feat(crm/TripApply): 新增出差申请后端审批功能

dev
Yangk 2 days ago
parent 1bb206bd0b
commit 0eb65296cc

@ -64,8 +64,7 @@ public class CrmBusinessTripApplyController extends BaseController {
*/
@SaCheckPermission("oa/crm:businessTripApply:query")
@GetMapping("/{tripId}")
public R<CrmBusinessTripApplyVo> getInfo(@NotNull(message = "主键不能为空")
@PathVariable("tripId") Long tripId) {
public R<CrmBusinessTripApplyVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable("tripId") Long tripId) {
return R.ok(crmBusinessTripApplyService.queryById(tripId));
}
@ -99,8 +98,7 @@ public class CrmBusinessTripApplyController extends BaseController {
@SaCheckPermission("oa/crm:businessTripApply:remove")
@Log(title = "出差申请", businessType = BusinessType.DELETE)
@DeleteMapping("/{tripIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空")
@PathVariable("tripIds") Long[] tripIds) {
public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable("tripIds") Long[] tripIds) {
return toAjax(crmBusinessTripApplyService.deleteWithValidByIds(List.of(tripIds), true));
}
@ -113,4 +111,16 @@ public class CrmBusinessTripApplyController extends BaseController {
return R.ok(list);
}
/**
*
*/
@SaCheckPermission("oa/crm:businessTripApply:add")
@Log(title = "出差申请", businessType = BusinessType.INSERT)
@RepeatSubmit()
@PostMapping("/submitAndFlowStart")
public R<CrmBusinessTripApplyVo> submitAndFlowStart(
@Validated(AddGroup.class) @RequestBody CrmBusinessTripApplyBo bo) {
return R.ok(crmBusinessTripApplyService.submitAndFlowStart(bo));
}
}

@ -17,8 +17,6 @@ import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
/**
* crm_business_trip_apply
*
@ -54,7 +52,6 @@ public class CrmBusinessTripApplyVo implements Serializable {
/**
* ID
*/
@ExcelProperty(value = "申请人ID")
private Long applicantId;
/**
@ -66,7 +63,6 @@ public class CrmBusinessTripApplyVo implements Serializable {
/**
* ID
*/
@ExcelProperty(value = "申请人部门ID")
private Long deptId;
/**
@ -108,15 +104,25 @@ public class CrmBusinessTripApplyVo implements Serializable {
/**
* ID
*/
@ExcelProperty(value = "项目ID")
private Long projectId;
/**
* ID
*/
@ExcelProperty(value = "客户ID")
private Long customerId;
/**
*
*/
@ExcelProperty(value = "项目名称")
private String projectName;
/**
*
*/
@ExcelProperty(value = "项目号")
private String projectCode;
/**
*
*/
@ -126,7 +132,8 @@ public class CrmBusinessTripApplyVo implements Serializable {
/**
*
*/
@ExcelProperty(value = "业务方向")
@ExcelProperty(value = "业务方向", converter = ExcelDictConvert.class)
@ExcelDictFormat(dictType = "business_direction")
private String businessDirection;
/**
@ -179,5 +186,4 @@ public class CrmBusinessTripApplyVo implements Serializable {
@ExcelDictFormat(readConverterExp = "多=个用逗号分隔")
private String ossId;
}

@ -66,4 +66,12 @@ public interface ICrmBusinessTripApplyService {
* @return
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
/**
*
*
* @param bo
* @return
*/
CrmBusinessTripApplyVo submitAndFlowStart(CrmBusinessTripApplyBo bo);
}

@ -2,9 +2,9 @@ package org.dromara.oa.crm.service.impl;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
@ -15,11 +15,25 @@ import org.dromara.oa.crm.domain.vo.CrmBusinessTripApplyVo;
import org.dromara.oa.crm.domain.CrmBusinessTripApply;
import org.dromara.oa.crm.mapper.CrmBusinessTripApplyMapper;
import org.dromara.oa.crm.service.ICrmBusinessTripApplyService;
import org.dromara.oa.erp.domain.ErpProjectInfo;
import java.util.List;
import java.util.Map;
import java.util.Collection;
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.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.transaction.annotation.Transactional;
import org.dromara.common.tenant.helper.TenantHelper;
import cn.hutool.core.convert.Convert;
/**
* Service
*
@ -28,10 +42,14 @@ import java.util.Collection;
*/
@RequiredArgsConstructor
@Service
@Slf4j
public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplyService {
private final CrmBusinessTripApplyMapper baseMapper;
@DubboReference(timeout = 30000)
private RemoteWorkflowService remoteWorkflowService;
/**
*
*
@ -39,23 +57,30 @@ public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplySer
* @return
*/
@Override
public CrmBusinessTripApplyVo queryById(Long tripId){
return baseMapper.selectVoById(tripId);
public CrmBusinessTripApplyVo queryById(Long tripId) {
MPJLambdaWrapper<CrmBusinessTripApply> lqw = JoinWrappers.lambda(CrmBusinessTripApply.class)
.selectAll(CrmBusinessTripApply.class)
.selectAs(ErpProjectInfo::getProjectName, CrmBusinessTripApplyVo::getProjectName)
.selectAs(ErpProjectInfo::getProjectCode, CrmBusinessTripApplyVo::getProjectCode)
.leftJoin(ErpProjectInfo.class, ErpProjectInfo::getProjectId, CrmBusinessTripApply::getProjectId)
.eq(CrmBusinessTripApply::getTripId, tripId);
return baseMapper.selectJoinOne(CrmBusinessTripApplyVo.class, lqw);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<CrmBusinessTripApplyVo> queryPageList(CrmBusinessTripApplyBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<CrmBusinessTripApply> lqw = buildQueryWrapper(bo);
Page<CrmBusinessTripApplyVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
*
*
* @param bo
* @param pageQuery
* @return
*/
@Override
public TableDataInfo<CrmBusinessTripApplyVo> queryPageList(CrmBusinessTripApplyBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<CrmBusinessTripApply> lqw = buildQueryWrapper(bo);
Page<CrmBusinessTripApplyVo> result = baseMapper.selectJoinPage(pageQuery.build(), CrmBusinessTripApplyVo.class,
lqw);
return TableDataInfo.build(result);
}
/**
*
@ -66,37 +91,46 @@ public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplySer
@Override
public List<CrmBusinessTripApplyVo> queryList(CrmBusinessTripApplyBo bo) {
MPJLambdaWrapper<CrmBusinessTripApply> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
return baseMapper.selectJoinList(CrmBusinessTripApplyVo.class, lqw);
}
private MPJLambdaWrapper<CrmBusinessTripApply> buildQueryWrapper(CrmBusinessTripApplyBo bo) {
Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<CrmBusinessTripApply> lqw = JoinWrappers.lambda(CrmBusinessTripApply.class)
.selectAll(CrmBusinessTripApply.class)
.eq(CrmBusinessTripApply::getDelFlag, "0")
.eq(StringUtils.isNotBlank(bo.getApplyCode()), CrmBusinessTripApply::getApplyCode, bo.getApplyCode())
.eq(StringUtils.isNotBlank(bo.getTripType()), CrmBusinessTripApply::getTripType, bo.getTripType())
.eq(bo.getApplicantId() != null, CrmBusinessTripApply::getApplicantId, bo.getApplicantId())
.like(StringUtils.isNotBlank(bo.getApplicantName()), CrmBusinessTripApply::getApplicantName, bo.getApplicantName())
.eq(bo.getDeptId() != null, CrmBusinessTripApply::getDeptId, bo.getDeptId())
.like(StringUtils.isNotBlank(bo.getDeptName()), CrmBusinessTripApply::getDeptName, bo.getDeptName())
.eq(StringUtils.isNotBlank(bo.getTripLocation()), CrmBusinessTripApply::getTripLocation, bo.getTripLocation())
.eq(bo.getStartTime() != null, CrmBusinessTripApply::getStartTime, bo.getStartTime())
.eq(bo.getEndTime() != null, CrmBusinessTripApply::getEndTime, bo.getEndTime())
.eq(bo.getDurationDays() != null, CrmBusinessTripApply::getDurationDays, bo.getDurationDays())
.eq(StringUtils.isNotBlank(bo.getTripReason()), CrmBusinessTripApply::getTripReason, bo.getTripReason())
.eq(bo.getProjectId() != null, CrmBusinessTripApply::getProjectId, bo.getProjectId())
.eq(bo.getCustomerId() != null, CrmBusinessTripApply::getCustomerId, bo.getCustomerId())
.eq(StringUtils.isNotBlank(bo.getExchangeObject()), CrmBusinessTripApply::getExchangeObject, bo.getExchangeObject())
.eq(StringUtils.isNotBlank(bo.getBusinessDirection()), CrmBusinessTripApply::getBusinessDirection, bo.getBusinessDirection())
.eq(StringUtils.isNotBlank(bo.getExchangePurpose()), CrmBusinessTripApply::getExchangePurpose, bo.getExchangePurpose())
.eq(StringUtils.isNotBlank(bo.getExchangeProcess()), CrmBusinessTripApply::getExchangeProcess, bo.getExchangeProcess())
.like(StringUtils.isNotBlank(bo.getMeetingName()), CrmBusinessTripApply::getMeetingName, bo.getMeetingName())
.eq(StringUtils.isNotBlank(bo.getFeedback()), CrmBusinessTripApply::getFeedback, bo.getFeedback())
.eq(StringUtils.isNotBlank(bo.getTripStatus()), CrmBusinessTripApply::getTripStatus, bo.getTripStatus())
.eq(StringUtils.isNotBlank(bo.getFlowStatus()), CrmBusinessTripApply::getFlowStatus, bo.getFlowStatus())
.eq(StringUtils.isNotBlank(bo.getOssId()), CrmBusinessTripApply::getOssId, bo.getOssId())
;
.selectAll(CrmBusinessTripApply.class)
.selectAs(ErpProjectInfo::getProjectName, CrmBusinessTripApplyVo::getProjectName)
.selectAs(ErpProjectInfo::getProjectCode, CrmBusinessTripApplyVo::getProjectCode)
.leftJoin(ErpProjectInfo.class, ErpProjectInfo::getProjectId, CrmBusinessTripApply::getProjectId)
.eq(CrmBusinessTripApply::getDelFlag, "0")
.eq(StringUtils.isNotBlank(bo.getApplyCode()), CrmBusinessTripApply::getApplyCode, bo.getApplyCode())
.eq(StringUtils.isNotBlank(bo.getTripType()), CrmBusinessTripApply::getTripType, bo.getTripType())
.eq(bo.getApplicantId() != null, CrmBusinessTripApply::getApplicantId, bo.getApplicantId())
.like(StringUtils.isNotBlank(bo.getApplicantName()), CrmBusinessTripApply::getApplicantName,
bo.getApplicantName())
.eq(bo.getDeptId() != null, CrmBusinessTripApply::getDeptId, bo.getDeptId())
.like(StringUtils.isNotBlank(bo.getDeptName()), CrmBusinessTripApply::getDeptName, bo.getDeptName())
.eq(StringUtils.isNotBlank(bo.getTripLocation()), CrmBusinessTripApply::getTripLocation,
bo.getTripLocation())
.eq(bo.getStartTime() != null, CrmBusinessTripApply::getStartTime, bo.getStartTime())
.eq(bo.getEndTime() != null, CrmBusinessTripApply::getEndTime, bo.getEndTime())
.eq(bo.getDurationDays() != null, CrmBusinessTripApply::getDurationDays, bo.getDurationDays())
.eq(StringUtils.isNotBlank(bo.getTripReason()), CrmBusinessTripApply::getTripReason, bo.getTripReason())
.eq(bo.getProjectId() != null, CrmBusinessTripApply::getProjectId, bo.getProjectId())
.eq(bo.getCustomerId() != null, CrmBusinessTripApply::getCustomerId, bo.getCustomerId())
.eq(StringUtils.isNotBlank(bo.getExchangeObject()), CrmBusinessTripApply::getExchangeObject,
bo.getExchangeObject())
.eq(StringUtils.isNotBlank(bo.getBusinessDirection()), CrmBusinessTripApply::getBusinessDirection,
bo.getBusinessDirection())
.eq(StringUtils.isNotBlank(bo.getExchangePurpose()), CrmBusinessTripApply::getExchangePurpose,
bo.getExchangePurpose())
.eq(StringUtils.isNotBlank(bo.getExchangeProcess()), CrmBusinessTripApply::getExchangeProcess,
bo.getExchangeProcess())
.like(StringUtils.isNotBlank(bo.getMeetingName()), CrmBusinessTripApply::getMeetingName,
bo.getMeetingName())
.eq(StringUtils.isNotBlank(bo.getFeedback()), CrmBusinessTripApply::getFeedback, bo.getFeedback())
.eq(StringUtils.isNotBlank(bo.getTripStatus()), CrmBusinessTripApply::getTripStatus, bo.getTripStatus())
.eq(StringUtils.isNotBlank(bo.getFlowStatus()), CrmBusinessTripApply::getFlowStatus, bo.getFlowStatus())
.eq(StringUtils.isNotBlank(bo.getOssId()), CrmBusinessTripApply::getOssId, bo.getOssId());
return lqw;
}
@ -133,8 +167,8 @@ public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplySer
/**
*
*/
private void validEntityBeforeSave(CrmBusinessTripApply entity){
//TODO 做一些数据校验,如唯一约束
private void validEntityBeforeSave(CrmBusinessTripApply entity) {
// TODO 做一些数据校验,如唯一约束
}
/**
@ -146,9 +180,94 @@ public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplySer
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
if (isValid) {
// TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteByIds(ids) > 0;
}
/**
*
*
* @param bo
* @return
*/
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public CrmBusinessTripApplyVo submitAndFlowStart(CrmBusinessTripApplyBo bo) {
if (bo.getTripId() == null) {
this.insertByBo(bo);
} else {
this.updateByBo(bo);
}
if (bo.getVariables() == null) {
bo.setVariables(new java.util.HashMap<>());
}
Map<String, Object> variables = bo.getVariables();
if (StringUtils.isNotBlank(bo.getTripType())) {
variables.put("tripType", bo.getTripType());
}
RemoteStartProcess startProcess = new RemoteStartProcess();
startProcess.setBusinessId(bo.getTripId().toString());
startProcess.setFlowCode(bo.getFlowCode());
startProcess.setVariables(variables);
startProcess.setBizExt(bo.getBizExt());
if (bo.getBizExt() != null) {
bo.getBizExt().setBusinessId(startProcess.getBusinessId());
}
boolean flag = remoteWorkflowService.startCompleteTask(startProcess);
if (!flag) {
throw new ServiceException("流程发起异常");
}
return this.queryById(bo.getTripId());
}
/**
*
*
* @param processEvent
*/
@EventListener(condition = "#processEvent.flowCode == 'OABT'")
public void processHandler(ProcessEvent processEvent) {
TenantHelper.dynamic(processEvent.getTenantId(), () -> {
log.info("【出差申请流程监听】开始处理: key={}, status={}", processEvent.getFlowCode(), processEvent.getStatus());
Long tripId = Convert.toLong(processEvent.getBusinessId());
CrmBusinessTripApply tripApply = baseMapper.selectById(tripId);
if (tripApply == null) {
log.error("未找到对应的出差申请单据id={}", tripId);
return;
}
tripApply.setFlowStatus(processEvent.getStatus());
String status = processEvent.getStatus();
// A. 审批中 (Waiting)
if (BusinessStatusEnum.WAITING.getStatus().equals(status)) {
tripApply.setTripStatus("2");
}
// B. 流程结束/审批通过 (Finish)
else if (BusinessStatusEnum.FINISH.getStatus().equals(status)) {
tripApply.setTripStatus("3");
}
// C. 驳回/撤销
else if (BusinessStatusEnum.BACK.getStatus().equals(status)
|| BusinessStatusEnum.CANCEL.getStatus().equals(status)) {
tripApply.setTripStatus("1");
}
// D. 作废/终止
else if (BusinessStatusEnum.INVALID.getStatus().equals(status)
|| BusinessStatusEnum.TERMINATION.getStatus().equals(status)) {
tripApply.setTripStatus("4");
}
baseMapper.updateById(tripApply);
});
}
}

@ -7,7 +7,39 @@
</resultMap>
<select id="selectCustomCrmBusinessTripApplyVoList" resultMap="CrmBusinessTripApplyResult">
select trip_id, tenant_id, apply_code, trip_type, applicant_id, applicant_name, dept_id, dept_name, trip_location, start_time, end_time, duration_days, trip_reason, project_id, customer_id, exchange_object, business_direction, exchange_purpose, exchange_process, meeting_name, feedback, trip_status, flow_status, remark, oss_id, del_flag, create_dept, create_by, create_time, update_by, update_time from crm_business_trip_apply t
select t.trip_id,
t.tenant_id,
t.apply_code,
t.trip_type,
t.applicant_id,
t.applicant_name,
t.dept_id,
t.trip_location,
t.start_time,
t.end_time,
t.duration_days,
t.trip_reason,
t.project_id,
t.customer_id,
t.exchange_object,
t.business_direction,
t.exchange_purpose,
t.exchange_process,
t.meeting_name,
t.feedback,
t.trip_status,
t.flow_status,
t.remark,
t.oss_id,
t.del_flag,
t.create_dept,
t.create_by,
t.create_time,
t.update_by,
t.update_time,
d.dept_name
from crm_business_trip_apply t
left join sys_dept d on t.dept_id = d.dept_id
${ew.getCustomSqlSegment}
</select>

Loading…
Cancel
Save