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

dev
Yangk 3 weeks ago
parent 1bb206bd0b
commit 0eb65296cc

@ -64,8 +64,7 @@ public class CrmBusinessTripApplyController extends BaseController {
*/ */
@SaCheckPermission("oa/crm:businessTripApply:query") @SaCheckPermission("oa/crm:businessTripApply:query")
@GetMapping("/{tripId}") @GetMapping("/{tripId}")
public R<CrmBusinessTripApplyVo> getInfo(@NotNull(message = "主键不能为空") public R<CrmBusinessTripApplyVo> getInfo(@NotNull(message = "主键不能为空") @PathVariable("tripId") Long tripId) {
@PathVariable("tripId") Long tripId) {
return R.ok(crmBusinessTripApplyService.queryById(tripId)); return R.ok(crmBusinessTripApplyService.queryById(tripId));
} }
@ -99,8 +98,7 @@ public class CrmBusinessTripApplyController extends BaseController {
@SaCheckPermission("oa/crm:businessTripApply:remove") @SaCheckPermission("oa/crm:businessTripApply:remove")
@Log(title = "出差申请", businessType = BusinessType.DELETE) @Log(title = "出差申请", businessType = BusinessType.DELETE)
@DeleteMapping("/{tripIds}") @DeleteMapping("/{tripIds}")
public R<Void> remove(@NotEmpty(message = "主键不能为空") public R<Void> remove(@NotEmpty(message = "主键不能为空") @PathVariable("tripIds") Long[] tripIds) {
@PathVariable("tripIds") Long[] tripIds) {
return toAjax(crmBusinessTripApplyService.deleteWithValidByIds(List.of(tripIds), true)); return toAjax(crmBusinessTripApplyService.deleteWithValidByIds(List.of(tripIds), true));
} }
@ -113,4 +111,16 @@ public class CrmBusinessTripApplyController extends BaseController {
return R.ok(list); 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.io.Serializable;
import java.util.Date; import java.util.Date;
/** /**
* crm_business_trip_apply * crm_business_trip_apply
* *
@ -54,7 +52,6 @@ public class CrmBusinessTripApplyVo implements Serializable {
/** /**
* ID * ID
*/ */
@ExcelProperty(value = "申请人ID")
private Long applicantId; private Long applicantId;
/** /**
@ -66,7 +63,6 @@ public class CrmBusinessTripApplyVo implements Serializable {
/** /**
* ID * ID
*/ */
@ExcelProperty(value = "申请人部门ID")
private Long deptId; private Long deptId;
/** /**
@ -108,15 +104,25 @@ public class CrmBusinessTripApplyVo implements Serializable {
/** /**
* ID * ID
*/ */
@ExcelProperty(value = "项目ID")
private Long projectId; private Long projectId;
/** /**
* ID * ID
*/ */
@ExcelProperty(value = "客户ID")
private Long customerId; 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; private String businessDirection;
/** /**
@ -179,5 +186,4 @@ public class CrmBusinessTripApplyVo implements Serializable {
@ExcelDictFormat(readConverterExp = "多=个用逗号分隔") @ExcelDictFormat(readConverterExp = "多=个用逗号分隔")
private String ossId; private String ossId;
} }

@ -66,4 +66,12 @@ public interface ICrmBusinessTripApplyService {
* @return * @return
*/ */
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid); 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.MapstructUtils;
import org.dromara.common.core.utils.StringUtils; import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.toolkit.JoinWrappers; import com.github.yulichang.toolkit.JoinWrappers;
import com.github.yulichang.wrapper.MPJLambdaWrapper; import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; 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.domain.CrmBusinessTripApply;
import org.dromara.oa.crm.mapper.CrmBusinessTripApplyMapper; import org.dromara.oa.crm.mapper.CrmBusinessTripApplyMapper;
import org.dromara.oa.crm.service.ICrmBusinessTripApplyService; import org.dromara.oa.crm.service.ICrmBusinessTripApplyService;
import org.dromara.oa.erp.domain.ErpProjectInfo;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Collection; 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 * Service
* *
@ -28,10 +42,14 @@ import java.util.Collection;
*/ */
@RequiredArgsConstructor @RequiredArgsConstructor
@Service @Service
@Slf4j
public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplyService { public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplyService {
private final CrmBusinessTripApplyMapper baseMapper; private final CrmBusinessTripApplyMapper baseMapper;
@DubboReference(timeout = 30000)
private RemoteWorkflowService remoteWorkflowService;
/** /**
* *
* *
@ -39,23 +57,30 @@ public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplySer
* @return * @return
*/ */
@Override @Override
public CrmBusinessTripApplyVo queryById(Long tripId){ public CrmBusinessTripApplyVo queryById(Long tripId) {
return baseMapper.selectVoById(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 bo
* @param pageQuery * @param pageQuery
* @return * @return
*/ */
@Override @Override
public TableDataInfo<CrmBusinessTripApplyVo> queryPageList(CrmBusinessTripApplyBo bo, PageQuery pageQuery) { public TableDataInfo<CrmBusinessTripApplyVo> queryPageList(CrmBusinessTripApplyBo bo, PageQuery pageQuery) {
MPJLambdaWrapper<CrmBusinessTripApply> lqw = buildQueryWrapper(bo); MPJLambdaWrapper<CrmBusinessTripApply> lqw = buildQueryWrapper(bo);
Page<CrmBusinessTripApplyVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw); Page<CrmBusinessTripApplyVo> result = baseMapper.selectJoinPage(pageQuery.build(), CrmBusinessTripApplyVo.class,
return TableDataInfo.build(result); lqw);
} return TableDataInfo.build(result);
}
/** /**
* *
@ -66,37 +91,46 @@ public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplySer
@Override @Override
public List<CrmBusinessTripApplyVo> queryList(CrmBusinessTripApplyBo bo) { public List<CrmBusinessTripApplyVo> queryList(CrmBusinessTripApplyBo bo) {
MPJLambdaWrapper<CrmBusinessTripApply> lqw = buildQueryWrapper(bo); MPJLambdaWrapper<CrmBusinessTripApply> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw); return baseMapper.selectJoinList(CrmBusinessTripApplyVo.class, lqw);
} }
private MPJLambdaWrapper<CrmBusinessTripApply> buildQueryWrapper(CrmBusinessTripApplyBo bo) { private MPJLambdaWrapper<CrmBusinessTripApply> buildQueryWrapper(CrmBusinessTripApplyBo bo) {
Map<String, Object> params = bo.getParams(); Map<String, Object> params = bo.getParams();
MPJLambdaWrapper<CrmBusinessTripApply> lqw = JoinWrappers.lambda(CrmBusinessTripApply.class) MPJLambdaWrapper<CrmBusinessTripApply> lqw = JoinWrappers.lambda(CrmBusinessTripApply.class)
.selectAll(CrmBusinessTripApply.class) .selectAll(CrmBusinessTripApply.class)
.eq(CrmBusinessTripApply::getDelFlag, "0") .selectAs(ErpProjectInfo::getProjectName, CrmBusinessTripApplyVo::getProjectName)
.eq(StringUtils.isNotBlank(bo.getApplyCode()), CrmBusinessTripApply::getApplyCode, bo.getApplyCode()) .selectAs(ErpProjectInfo::getProjectCode, CrmBusinessTripApplyVo::getProjectCode)
.eq(StringUtils.isNotBlank(bo.getTripType()), CrmBusinessTripApply::getTripType, bo.getTripType()) .leftJoin(ErpProjectInfo.class, ErpProjectInfo::getProjectId, CrmBusinessTripApply::getProjectId)
.eq(bo.getApplicantId() != null, CrmBusinessTripApply::getApplicantId, bo.getApplicantId()) .eq(CrmBusinessTripApply::getDelFlag, "0")
.like(StringUtils.isNotBlank(bo.getApplicantName()), CrmBusinessTripApply::getApplicantName, bo.getApplicantName()) .eq(StringUtils.isNotBlank(bo.getApplyCode()), CrmBusinessTripApply::getApplyCode, bo.getApplyCode())
.eq(bo.getDeptId() != null, CrmBusinessTripApply::getDeptId, bo.getDeptId()) .eq(StringUtils.isNotBlank(bo.getTripType()), CrmBusinessTripApply::getTripType, bo.getTripType())
.like(StringUtils.isNotBlank(bo.getDeptName()), CrmBusinessTripApply::getDeptName, bo.getDeptName()) .eq(bo.getApplicantId() != null, CrmBusinessTripApply::getApplicantId, bo.getApplicantId())
.eq(StringUtils.isNotBlank(bo.getTripLocation()), CrmBusinessTripApply::getTripLocation, bo.getTripLocation()) .like(StringUtils.isNotBlank(bo.getApplicantName()), CrmBusinessTripApply::getApplicantName,
.eq(bo.getStartTime() != null, CrmBusinessTripApply::getStartTime, bo.getStartTime()) bo.getApplicantName())
.eq(bo.getEndTime() != null, CrmBusinessTripApply::getEndTime, bo.getEndTime()) .eq(bo.getDeptId() != null, CrmBusinessTripApply::getDeptId, bo.getDeptId())
.eq(bo.getDurationDays() != null, CrmBusinessTripApply::getDurationDays, bo.getDurationDays()) .like(StringUtils.isNotBlank(bo.getDeptName()), CrmBusinessTripApply::getDeptName, bo.getDeptName())
.eq(StringUtils.isNotBlank(bo.getTripReason()), CrmBusinessTripApply::getTripReason, bo.getTripReason()) .eq(StringUtils.isNotBlank(bo.getTripLocation()), CrmBusinessTripApply::getTripLocation,
.eq(bo.getProjectId() != null, CrmBusinessTripApply::getProjectId, bo.getProjectId()) bo.getTripLocation())
.eq(bo.getCustomerId() != null, CrmBusinessTripApply::getCustomerId, bo.getCustomerId()) .eq(bo.getStartTime() != null, CrmBusinessTripApply::getStartTime, bo.getStartTime())
.eq(StringUtils.isNotBlank(bo.getExchangeObject()), CrmBusinessTripApply::getExchangeObject, bo.getExchangeObject()) .eq(bo.getEndTime() != null, CrmBusinessTripApply::getEndTime, bo.getEndTime())
.eq(StringUtils.isNotBlank(bo.getBusinessDirection()), CrmBusinessTripApply::getBusinessDirection, bo.getBusinessDirection()) .eq(bo.getDurationDays() != null, CrmBusinessTripApply::getDurationDays, bo.getDurationDays())
.eq(StringUtils.isNotBlank(bo.getExchangePurpose()), CrmBusinessTripApply::getExchangePurpose, bo.getExchangePurpose()) .eq(StringUtils.isNotBlank(bo.getTripReason()), CrmBusinessTripApply::getTripReason, bo.getTripReason())
.eq(StringUtils.isNotBlank(bo.getExchangeProcess()), CrmBusinessTripApply::getExchangeProcess, bo.getExchangeProcess()) .eq(bo.getProjectId() != null, CrmBusinessTripApply::getProjectId, bo.getProjectId())
.like(StringUtils.isNotBlank(bo.getMeetingName()), CrmBusinessTripApply::getMeetingName, bo.getMeetingName()) .eq(bo.getCustomerId() != null, CrmBusinessTripApply::getCustomerId, bo.getCustomerId())
.eq(StringUtils.isNotBlank(bo.getFeedback()), CrmBusinessTripApply::getFeedback, bo.getFeedback()) .eq(StringUtils.isNotBlank(bo.getExchangeObject()), CrmBusinessTripApply::getExchangeObject,
.eq(StringUtils.isNotBlank(bo.getTripStatus()), CrmBusinessTripApply::getTripStatus, bo.getTripStatus()) bo.getExchangeObject())
.eq(StringUtils.isNotBlank(bo.getFlowStatus()), CrmBusinessTripApply::getFlowStatus, bo.getFlowStatus()) .eq(StringUtils.isNotBlank(bo.getBusinessDirection()), CrmBusinessTripApply::getBusinessDirection,
.eq(StringUtils.isNotBlank(bo.getOssId()), CrmBusinessTripApply::getOssId, bo.getOssId()) 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; return lqw;
} }
@ -133,8 +167,8 @@ public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplySer
/** /**
* *
*/ */
private void validEntityBeforeSave(CrmBusinessTripApply entity){ private void validEntityBeforeSave(CrmBusinessTripApply entity) {
//TODO 做一些数据校验,如唯一约束 // TODO 做一些数据校验,如唯一约束
} }
/** /**
@ -146,9 +180,94 @@ public class CrmBusinessTripApplyServiceImpl implements ICrmBusinessTripApplySer
*/ */
@Override @Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) { public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){ if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验 // TODO 做一些业务上的校验,判断是否需要校验
} }
return baseMapper.deleteByIds(ids) > 0; 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> </resultMap>
<select id="selectCustomCrmBusinessTripApplyVoList" resultMap="CrmBusinessTripApplyResult"> <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} ${ew.getCustomSqlSegment}
</select> </select>

Loading…
Cancel
Save