|
|
|
|
@ -1,6 +1,5 @@
|
|
|
|
|
package org.dromara.oa.erp.service.impl;
|
|
|
|
|
|
|
|
|
|
import cn.dev33.satoken.stp.StpUtil;
|
|
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
|
|
import cn.hutool.core.convert.Convert;
|
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
|
|
@ -10,7 +9,6 @@ import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
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;
|
|
|
|
|
@ -35,15 +33,17 @@ 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.springframework.transaction.annotation.Transactional;
|
|
|
|
|
import org.springframework.transaction.support.TransactionSynchronization;
|
|
|
|
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
|
|
|
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.Date;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@ -59,7 +59,6 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
|
|
|
|
|
private static final String ACCOUNT_INSTALLMENT_CODE_RULE = "1031";
|
|
|
|
|
private static final String FLOW_CODE_FKSH = "FKSH";
|
|
|
|
|
private static final String PERM_DISPATCH = "oa/erp:finAccountInstallment:dispatch";
|
|
|
|
|
|
|
|
|
|
/** 分款状态字典 installment_status:0未分款 1已派发 2分款完成 */
|
|
|
|
|
private static final String INSTALLMENT_STATUS_NOT_ALLOCATED = "0";
|
|
|
|
|
@ -78,6 +77,12 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
@DubboReference
|
|
|
|
|
private RemoteWorkflowService remoteWorkflowService;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 查询分款信息详情,并填充客户经理昵称
|
|
|
|
|
*
|
|
|
|
|
* @param accountInstallmentId 回款主键
|
|
|
|
|
* @return 分款信息
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public ErpFinAccountInstallmentVo queryById(Long accountInstallmentId) {
|
|
|
|
|
ErpFinAccountInstallmentVo vo = baseMapper.selectVoById(accountInstallmentId);
|
|
|
|
|
@ -87,6 +92,13 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
return vo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 分页查询分款信息列表
|
|
|
|
|
*
|
|
|
|
|
* @param bo 查询条件
|
|
|
|
|
* @param pageQuery 分页参数
|
|
|
|
|
* @return 分款信息分页列表
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public TableDataInfo<ErpFinAccountInstallmentVo> queryPageList(ErpFinAccountInstallmentBo bo, PageQuery pageQuery) {
|
|
|
|
|
MPJLambdaWrapper<ErpFinAccountInstallment> lqw = buildQueryWrapper(bo);
|
|
|
|
|
@ -95,6 +107,12 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
return TableDataInfo.build(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 查询符合条件的分款信息列表
|
|
|
|
|
*
|
|
|
|
|
* @param bo 查询条件
|
|
|
|
|
* @return 分款信息列表
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public List<ErpFinAccountInstallmentVo> queryList(ErpFinAccountInstallmentBo bo) {
|
|
|
|
|
MPJLambdaWrapper<ErpFinAccountInstallment> lqw = buildQueryWrapper(bo);
|
|
|
|
|
@ -103,6 +121,12 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 构建分款信息查询条件
|
|
|
|
|
*
|
|
|
|
|
* @param bo 查询条件
|
|
|
|
|
* @return 查询包装器
|
|
|
|
|
*/
|
|
|
|
|
private MPJLambdaWrapper<ErpFinAccountInstallment> buildQueryWrapper(ErpFinAccountInstallmentBo bo) {
|
|
|
|
|
MPJLambdaWrapper<ErpFinAccountInstallment> lqw = JoinWrappers.lambda(ErpFinAccountInstallment.class)
|
|
|
|
|
.selectAll(ErpFinAccountInstallment.class)
|
|
|
|
|
@ -119,13 +143,15 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
return lqw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 批量填充客户经理用户ID、昵称
|
|
|
|
|
*
|
|
|
|
|
* @param rows 分款信息列表
|
|
|
|
|
*/
|
|
|
|
|
private void fillManagerInfo(List<ErpFinAccountInstallmentVo> rows) {
|
|
|
|
|
if (CollUtil.isEmpty(rows)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Long currentUserId = LoginHelper.getUserId();
|
|
|
|
|
boolean canDispatchAll = LoginHelper.isSuperAdmin() || StpUtil.hasPermission(PERM_DISPATCH);
|
|
|
|
|
|
|
|
|
|
for (ErpFinAccountInstallmentVo vo : rows) {
|
|
|
|
|
List<Long> userIds = parseManagerUserIds(vo.getAccountManagerIds());
|
|
|
|
|
vo.setManagerUserIds(userIds);
|
|
|
|
|
@ -133,24 +159,15 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
String idsStr = userIds.stream().map(String::valueOf).collect(Collectors.joining(","));
|
|
|
|
|
vo.setManagerNickNames(remoteUserService.selectNicknameByIds(idsStr));
|
|
|
|
|
}
|
|
|
|
|
vo.setCanAllocate(resolveCanAllocate(vo, userIds, currentUserId, canDispatchAll));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean resolveCanAllocate(ErpFinAccountInstallmentVo vo, List<Long> managerUserIds,
|
|
|
|
|
Long currentUserId, boolean canDispatchAll) {
|
|
|
|
|
if (!BusinessStatusEnum.WAITING.getStatus().equals(vo.getFlowStatus())) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (!canAllocateByInstallmentStatus(vo.getInstallmentStatus())) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (canDispatchAll) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return managerUserIds.contains(currentUserId);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将客户经理用户ID列表拼接为逗号分隔字符串
|
|
|
|
|
*
|
|
|
|
|
* @param ids 用户ID列表
|
|
|
|
|
* @return 逗号分隔的ID字符串,空列表返回 null
|
|
|
|
|
*/
|
|
|
|
|
private static String joinManagerUserIds(List<Long> ids) {
|
|
|
|
|
if (CollUtil.isEmpty(ids)) {
|
|
|
|
|
return null;
|
|
|
|
|
@ -158,6 +175,12 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
return ids.stream().map(String::valueOf).collect(Collectors.joining(","));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 解析逗号分隔的客户经理用户ID字符串
|
|
|
|
|
*
|
|
|
|
|
* @param idsStr 逗号分隔的用户ID
|
|
|
|
|
* @return 用户ID列表,空字符串返回空列表
|
|
|
|
|
*/
|
|
|
|
|
private static List<Long> parseManagerUserIds(String idsStr) {
|
|
|
|
|
if (StringUtils.isBlank(idsStr)) {
|
|
|
|
|
return List.of();
|
|
|
|
|
@ -169,21 +192,20 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
.toList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 新增回款分款信息:默认草稿流程、未分款状态,未填编号时按编码规则生成唯一回款编号
|
|
|
|
|
*
|
|
|
|
|
* @param bo 分款信息
|
|
|
|
|
* @return 是否新增成功
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public Boolean insertByBo(ErpFinAccountInstallmentBo bo) {
|
|
|
|
|
ErpFinAccountInstallment add = MapstructUtils.convert(bo, ErpFinAccountInstallment.class);
|
|
|
|
|
if (StringUtils.isBlank(add.getFlowStatus())) {
|
|
|
|
|
add.setFlowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
|
|
|
|
}
|
|
|
|
|
if (StringUtils.isBlank(add.getInstallmentStatus())) {
|
|
|
|
|
add.setInstallmentStatus(INSTALLMENT_STATUS_NOT_ALLOCATED);
|
|
|
|
|
}
|
|
|
|
|
if (StringUtils.isBlank(add.getInstallmentCode())) {
|
|
|
|
|
String code = remoteCodeRuleService.selectCodeRuleCode(ACCOUNT_INSTALLMENT_CODE_RULE);
|
|
|
|
|
if (StringUtils.isBlank(code)) {
|
|
|
|
|
throw new ServiceException("生成回款编号失败");
|
|
|
|
|
}
|
|
|
|
|
add.setInstallmentCode(code);
|
|
|
|
|
add.setInstallmentCode(generateInstallmentCode());
|
|
|
|
|
}
|
|
|
|
|
validEntityBeforeSave(add);
|
|
|
|
|
boolean flag = baseMapper.insert(add) > 0;
|
|
|
|
|
@ -193,6 +215,12 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 批量导入回款数据,每条记录单独生成唯一回款编号并校验必填项
|
|
|
|
|
*
|
|
|
|
|
* @param installmentVolist 导入的回款信息列表
|
|
|
|
|
* @return 导入结果提示信息
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public String importInstallmentData(List<ErpFinAccountInstallmentVo> installmentVolist) {
|
|
|
|
|
try {
|
|
|
|
|
@ -200,11 +228,6 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
throw new ServiceException("导入数据不能为空!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String code = remoteCodeRuleService.selectCodeRuleCode(ACCOUNT_INSTALLMENT_CODE_RULE);
|
|
|
|
|
if (StringUtils.isBlank(code)) {
|
|
|
|
|
throw new ServiceException("生成回款编号失败");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int successNum = 0;
|
|
|
|
|
int failureNum = 0;
|
|
|
|
|
StringBuilder successMsg = new StringBuilder();
|
|
|
|
|
@ -221,7 +244,10 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErpFinAccountInstallment add = MapstructUtils.convert(installmentVo, ErpFinAccountInstallment.class);
|
|
|
|
|
add.setInstallmentCode(code);
|
|
|
|
|
if (StringUtils.isBlank(add.getInstallmentCode())) {
|
|
|
|
|
add.setInstallmentCode(generateInstallmentCode());
|
|
|
|
|
}
|
|
|
|
|
validEntityBeforeSave(add);
|
|
|
|
|
add.setFlowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
|
|
|
|
add.setInstallmentStatus(INSTALLMENT_STATUS_NOT_ALLOCATED);
|
|
|
|
|
add.setDelFlag("0");
|
|
|
|
|
@ -247,6 +273,12 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 修改回款分款信息,仅允许流程草稿/退回/撤销且未分款状态的记录
|
|
|
|
|
*
|
|
|
|
|
* @param bo 分款信息
|
|
|
|
|
* @return 是否修改成功
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public Boolean updateByBo(ErpFinAccountInstallmentBo bo) {
|
|
|
|
|
ErpFinAccountInstallment existing = baseMapper.selectById(bo.getAccountInstallmentId());
|
|
|
|
|
@ -264,8 +296,14 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
return baseMapper.updateById(update) > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 将草稿回款派发给客户经理,更新派发信息并发起分款审核流程(FKSH)
|
|
|
|
|
*
|
|
|
|
|
* @param bo 派发参数(回款ID、客户经理)
|
|
|
|
|
* @return 是否派发成功
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
@GlobalTransactional(rollbackFor = Exception.class)
|
|
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
|
|
public Boolean dispatchToManagers(ErpFinAccountInstallmentDispatchBo bo) {
|
|
|
|
|
List<Long> installmentIds = bo.getAccountInstallmentIds().stream().distinct().toList();
|
|
|
|
|
List<Long> managerUserIds = bo.getManagerUserIds().stream().distinct().toList();
|
|
|
|
|
@ -291,12 +329,10 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
Date now = new Date();
|
|
|
|
|
String accountManagerIds = joinManagerUserIds(managerUserIds);
|
|
|
|
|
|
|
|
|
|
Map<Long, ErpFinAccountInstallment> installmentMap = installments.stream()
|
|
|
|
|
.collect(Collectors.toMap(ErpFinAccountInstallment::getAccountInstallmentId, i -> i));
|
|
|
|
|
|
|
|
|
|
for (Long installmentId : installmentIds) {
|
|
|
|
|
List<ErpFinAccountInstallment> flowTargets = new ArrayList<>(installments.size());
|
|
|
|
|
for (ErpFinAccountInstallment inst : installments) {
|
|
|
|
|
ErpFinAccountInstallment update = new ErpFinAccountInstallment();
|
|
|
|
|
update.setAccountInstallmentId(installmentId);
|
|
|
|
|
update.setAccountInstallmentId(inst.getAccountInstallmentId());
|
|
|
|
|
update.setAccountManagerIds(accountManagerIds);
|
|
|
|
|
update.setFlowStatus(BusinessStatusEnum.WAITING.getStatus());
|
|
|
|
|
update.setInstallmentStatus(INSTALLMENT_STATUS_DISPATCHED);
|
|
|
|
|
@ -304,31 +340,55 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
update.setDispatchDeptId(dispatchDeptId);
|
|
|
|
|
update.setDispatchDate(now);
|
|
|
|
|
baseMapper.updateById(update);
|
|
|
|
|
|
|
|
|
|
ErpFinAccountInstallment inst = installmentMap.get(installmentId);
|
|
|
|
|
startDispatchFlow(installmentId, inst, bo);
|
|
|
|
|
flowTargets.add(inst);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 先提交本地事务释放行锁,再发起流程,避免 Seata 全局锁与流程回调争用同一行
|
|
|
|
|
registerDispatchFlowAfterCommit(flowTargets, accountManagerIds);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 派发后发起分款审核流程(流程参数由前端组装传入)
|
|
|
|
|
* 事务提交后批量发起分款审核流程,避免 update 与流程监听在同一全局事务内锁等待
|
|
|
|
|
*/
|
|
|
|
|
private void startDispatchFlow(Long installmentId, ErpFinAccountInstallment inst,
|
|
|
|
|
ErpFinAccountInstallmentDispatchBo bo) {
|
|
|
|
|
Map<String, Object> variables = bo.getVariables() != null
|
|
|
|
|
? new HashMap<>(bo.getVariables())
|
|
|
|
|
: new HashMap<>();
|
|
|
|
|
if (!variables.containsKey("ignore")) {
|
|
|
|
|
variables.put("ignore", true);
|
|
|
|
|
private void registerDispatchFlowAfterCommit(List<ErpFinAccountInstallment> installments, String accountManagerIds) {
|
|
|
|
|
if (CollUtil.isEmpty(installments)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Runnable startFlows = () -> {
|
|
|
|
|
for (ErpFinAccountInstallment inst : installments) {
|
|
|
|
|
startDispatchFlow(inst, accountManagerIds);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
if (TransactionSynchronizationManager.isSynchronizationActive()) {
|
|
|
|
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
|
|
|
|
|
@Override
|
|
|
|
|
public void afterCommit() {
|
|
|
|
|
startFlows.run();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
startFlows.run();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 派发后发起分款审核流程(FKSH)
|
|
|
|
|
*
|
|
|
|
|
* @param inst 回款实体
|
|
|
|
|
* @param accountManagerIds 客户经理用户ID(逗号分隔,写入流程变量 accountManagerId)
|
|
|
|
|
*/
|
|
|
|
|
private void startDispatchFlow(ErpFinAccountInstallment inst, String accountManagerIds) {
|
|
|
|
|
Map<String, Object> variables = new HashMap<>();
|
|
|
|
|
variables.put("ignore", true);
|
|
|
|
|
variables.put("accountManagerId", accountManagerIds);
|
|
|
|
|
|
|
|
|
|
RemoteStartProcess startProcess = new RemoteStartProcess();
|
|
|
|
|
startProcess.setBusinessId(installmentId.toString());
|
|
|
|
|
startProcess.setFlowCode(StringUtils.isNotBlank(bo.getFlowCode()) ? bo.getFlowCode() : FLOW_CODE_FKSH);
|
|
|
|
|
startProcess.setBusinessId(inst.getAccountInstallmentId().toString());
|
|
|
|
|
startProcess.setFlowCode(FLOW_CODE_FKSH);
|
|
|
|
|
startProcess.setVariables(variables);
|
|
|
|
|
|
|
|
|
|
RemoteFlowInstanceBizExt bizExt = resolveDispatchBizExt(installmentId, inst, bo);
|
|
|
|
|
RemoteFlowInstanceBizExt bizExt = buildDispatchBizExt(inst);
|
|
|
|
|
bizExt.setBusinessId(startProcess.getBusinessId());
|
|
|
|
|
startProcess.setBizExt(bizExt);
|
|
|
|
|
|
|
|
|
|
@ -338,31 +398,23 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private RemoteFlowInstanceBizExt resolveDispatchBizExt(Long installmentId, ErpFinAccountInstallment inst,
|
|
|
|
|
ErpFinAccountInstallmentDispatchBo bo) {
|
|
|
|
|
String installmentIdStr = installmentId.toString();
|
|
|
|
|
if (CollUtil.isNotEmpty(bo.getFlowBizList())) {
|
|
|
|
|
for (RemoteFlowInstanceBizExt item : bo.getFlowBizList()) {
|
|
|
|
|
if (item != null && installmentIdStr.equals(item.getBusinessId())) {
|
|
|
|
|
RemoteFlowInstanceBizExt bizExt = new RemoteFlowInstanceBizExt();
|
|
|
|
|
bizExt.setBusinessCode(item.getBusinessCode());
|
|
|
|
|
bizExt.setBusinessTitle(item.getBusinessTitle());
|
|
|
|
|
return bizExt;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 构建派发流程业务扩展信息
|
|
|
|
|
*
|
|
|
|
|
* @param inst 回款实体
|
|
|
|
|
* @return 流程业务扩展信息
|
|
|
|
|
*/
|
|
|
|
|
private RemoteFlowInstanceBizExt buildDispatchBizExt(ErpFinAccountInstallment inst) {
|
|
|
|
|
RemoteFlowInstanceBizExt bizExt = new RemoteFlowInstanceBizExt();
|
|
|
|
|
if (inst != null) {
|
|
|
|
|
bizExt.setBusinessCode(inst.getInstallmentCode());
|
|
|
|
|
bizExt.setBusinessTitle("分款审核-" + inst.getCustomerName());
|
|
|
|
|
} else {
|
|
|
|
|
bizExt.setBusinessTitle("分款审核");
|
|
|
|
|
}
|
|
|
|
|
bizExt.setBusinessCode(inst.getInstallmentCode());
|
|
|
|
|
bizExt.setBusinessTitle(inst.getCustomerName() + "分款审核");
|
|
|
|
|
return bizExt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 分款审核流程状态监听
|
|
|
|
|
* 分款审核流程(FKSH)状态监听:同步流程状态,并按流程状态更新分款进度
|
|
|
|
|
*
|
|
|
|
|
* @param processEvent 流程事件
|
|
|
|
|
*/
|
|
|
|
|
@EventListener(condition = "#processEvent.flowCode == 'FKSH'")
|
|
|
|
|
public void processHandler(ProcessEvent processEvent) {
|
|
|
|
|
@ -378,108 +430,94 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
|
|
|
|
|
ErpFinAccountInstallment update = new ErpFinAccountInstallment();
|
|
|
|
|
update.setAccountInstallmentId(installmentId);
|
|
|
|
|
update.setFlowStatus(processEvent.getStatus());
|
|
|
|
|
String status = processEvent.getStatus();
|
|
|
|
|
|
|
|
|
|
if (BusinessStatusEnum.BACK.getStatus().equals(status)
|
|
|
|
|
|| BusinessStatusEnum.CANCEL.getStatus().equals(status)) {
|
|
|
|
|
update.setInstallmentStatus(INSTALLMENT_STATUS_NOT_ALLOCATED);
|
|
|
|
|
update.setAccountManagerIds(null);
|
|
|
|
|
baseMapper.updateById(update);
|
|
|
|
|
} else if (BusinessStatusEnum.INVALID.getStatus().equals(status)
|
|
|
|
|
|| BusinessStatusEnum.TERMINATION.getStatus().equals(status)) {
|
|
|
|
|
update.setInstallmentStatus(INSTALLMENT_STATUS_NOT_ALLOCATED);
|
|
|
|
|
baseMapper.updateById(update);
|
|
|
|
|
} else {
|
|
|
|
|
baseMapper.updateById(update);
|
|
|
|
|
}
|
|
|
|
|
applyInstallmentStatusByFlowStatus(update, processEvent.getStatus());
|
|
|
|
|
baseMapper.updateById(update);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void validateAllocatePermission(Long accountInstallmentId) {
|
|
|
|
|
ErpFinAccountInstallment inst = baseMapper.selectById(accountInstallmentId);
|
|
|
|
|
if (inst == null) {
|
|
|
|
|
throw new ServiceException("回款记录不存在");
|
|
|
|
|
}
|
|
|
|
|
if (!BusinessStatusEnum.WAITING.getStatus().equals(inst.getFlowStatus())) {
|
|
|
|
|
throw new ServiceException("当前回款流程未处于待处理状态,无法进行分款操作");
|
|
|
|
|
}
|
|
|
|
|
if (!canAllocateByInstallmentStatus(inst.getInstallmentStatus())) {
|
|
|
|
|
throw new ServiceException("当前回款尚未派发或分款已完成,无法进行分款操作");
|
|
|
|
|
}
|
|
|
|
|
if (LoginHelper.isSuperAdmin() || StpUtil.hasPermission(PERM_DISPATCH)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Long userId = LoginHelper.getUserId();
|
|
|
|
|
if (!parseManagerUserIds(inst.getAccountManagerIds()).contains(userId)) {
|
|
|
|
|
throw new ServiceException("您不是该回款的指定客户经理,无法进行分款操作");
|
|
|
|
|
/**
|
|
|
|
|
* 按流程状态同步主表 flow_status、installment_status
|
|
|
|
|
*
|
|
|
|
|
* @param update 待更新实体(需已设置 accountInstallmentId)
|
|
|
|
|
* @param flowStatus 流程状态
|
|
|
|
|
*/
|
|
|
|
|
private void applyInstallmentStatusByFlowStatus(ErpFinAccountInstallment update, String flowStatus) {
|
|
|
|
|
update.setFlowStatus(flowStatus);
|
|
|
|
|
if (BusinessStatusEnum.FINISH.getStatus().equals(flowStatus)) {
|
|
|
|
|
update.setInstallmentStatus(INSTALLMENT_STATUS_COMPLETE);
|
|
|
|
|
} else if (BusinessStatusEnum.WAITING.getStatus().equals(flowStatus)) {
|
|
|
|
|
update.setInstallmentStatus(INSTALLMENT_STATUS_DISPATCHED);
|
|
|
|
|
} else if (BusinessStatusEnum.DRAFT.getStatus().equals(flowStatus)
|
|
|
|
|
|| BusinessStatusEnum.BACK.getStatus().equals(flowStatus)
|
|
|
|
|
|| BusinessStatusEnum.CANCEL.getStatus().equals(flowStatus)
|
|
|
|
|
|| BusinessStatusEnum.INVALID.getStatus().equals(flowStatus)
|
|
|
|
|
|| BusinessStatusEnum.TERMINATION.getStatus().equals(flowStatus)) {
|
|
|
|
|
update.setInstallmentStatus(INSTALLMENT_STATUS_NOT_ALLOCATED);
|
|
|
|
|
if (BusinessStatusEnum.BACK.getStatus().equals(flowStatus)
|
|
|
|
|
|| BusinessStatusEnum.CANCEL.getStatus().equals(flowStatus)) {
|
|
|
|
|
update.setAccountManagerIds(null);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void recalculateInstallmentStatus(Long accountInstallmentId) {
|
|
|
|
|
ErpFinAccountInstallment inst = baseMapper.selectById(accountInstallmentId);
|
|
|
|
|
if (inst == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
String status = inst.getInstallmentStatus();
|
|
|
|
|
if (isInstallmentNotAllocated(status)
|
|
|
|
|
|| !BusinessStatusEnum.WAITING.getStatus().equals(inst.getFlowStatus())) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<ErpFinAccountInstallmentDetail> details = detailMapper.selectList(
|
|
|
|
|
Wrappers.lambdaQuery(ErpFinAccountInstallmentDetail.class)
|
|
|
|
|
.eq(ErpFinAccountInstallmentDetail::getAccountInstallmentId, accountInstallmentId));
|
|
|
|
|
|
|
|
|
|
BigDecimal allocated = details.stream()
|
|
|
|
|
.map(ErpFinAccountInstallmentDetail::getDetailAmount)
|
|
|
|
|
.filter(Objects::nonNull)
|
|
|
|
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
|
|
|
|
|
|
|
|
BigDecimal payment = inst.getPaymentAmount() == null
|
|
|
|
|
? BigDecimal.ZERO
|
|
|
|
|
: BigDecimal.valueOf(inst.getPaymentAmount());
|
|
|
|
|
|
|
|
|
|
String newStatus;
|
|
|
|
|
if (allocated.compareTo(BigDecimal.ZERO) <= 0) {
|
|
|
|
|
newStatus = INSTALLMENT_STATUS_DISPATCHED;
|
|
|
|
|
} else if (allocated.compareTo(payment) >= 0) {
|
|
|
|
|
newStatus = INSTALLMENT_STATUS_COMPLETE;
|
|
|
|
|
} else {
|
|
|
|
|
newStatus = INSTALLMENT_STATUS_DISPATCHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErpFinAccountInstallment update = new ErpFinAccountInstallment();
|
|
|
|
|
update.setAccountInstallmentId(accountInstallmentId);
|
|
|
|
|
if (!Objects.equals(status, newStatus)) {
|
|
|
|
|
update.setInstallmentStatus(newStatus);
|
|
|
|
|
baseMapper.updateById(update);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 流程是否可编辑/派发(同出差申请:草稿、退回、撤销) */
|
|
|
|
|
/**
|
|
|
|
|
* 流程是否可编辑/派发(草稿、退回、撤销)
|
|
|
|
|
*
|
|
|
|
|
* @param flowStatus 流程状态
|
|
|
|
|
* @return 是否可编辑或派发
|
|
|
|
|
*/
|
|
|
|
|
private static boolean isFlowEditable(String flowStatus) {
|
|
|
|
|
return BusinessStatusEnum.isDraftOrCancelOrBack(flowStatus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 分款状态:未分款(installment_status = 0) */
|
|
|
|
|
/**
|
|
|
|
|
* 分款状态是否为未分款(installment_status = 0)
|
|
|
|
|
*
|
|
|
|
|
* @param installmentStatus 分款状态
|
|
|
|
|
* @return 是否未分款
|
|
|
|
|
*/
|
|
|
|
|
private static boolean isInstallmentNotAllocated(String installmentStatus) {
|
|
|
|
|
return INSTALLMENT_STATUS_NOT_ALLOCATED.equals(installmentStatus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 分款状态:已派发,可进行明细维护(installment_status = 1) */
|
|
|
|
|
private static boolean canAllocateByInstallmentStatus(String installmentStatus) {
|
|
|
|
|
return INSTALLMENT_STATUS_DISPATCHED.equals(installmentStatus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void validEntityBeforeSave(ErpFinAccountInstallment entity) {
|
|
|
|
|
// 预留业务校验
|
|
|
|
|
/**
|
|
|
|
|
* 按编码规则(1031)生成唯一回款编号
|
|
|
|
|
*
|
|
|
|
|
* @return 回款编号
|
|
|
|
|
*/
|
|
|
|
|
private String generateInstallmentCode() {
|
|
|
|
|
String code = remoteCodeRuleService.selectCodeRuleCode(ACCOUNT_INSTALLMENT_CODE_RULE);
|
|
|
|
|
if (StringUtils.isBlank(code)) {
|
|
|
|
|
throw new ServiceException("生成回款编号失败");
|
|
|
|
|
}
|
|
|
|
|
return code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 删除回款主表(逻辑删除),并级联逻辑删除其分款明细
|
|
|
|
|
* 保存前数据校验:回款编号全局唯一
|
|
|
|
|
*
|
|
|
|
|
* @param entity 回款实体
|
|
|
|
|
*/
|
|
|
|
|
private void validEntityBeforeSave(ErpFinAccountInstallment entity) {
|
|
|
|
|
if (StringUtils.isBlank(entity.getInstallmentCode())) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
boolean codeExists = baseMapper.exists(
|
|
|
|
|
Wrappers.lambdaQuery(ErpFinAccountInstallment.class)
|
|
|
|
|
.eq(ErpFinAccountInstallment::getInstallmentCode, entity.getInstallmentCode())
|
|
|
|
|
.ne(entity.getAccountInstallmentId() != null, ErpFinAccountInstallment::getAccountInstallmentId, entity.getAccountInstallmentId())
|
|
|
|
|
);
|
|
|
|
|
if (codeExists) {
|
|
|
|
|
throw new ServiceException("回款编号已存在:" + entity.getInstallmentCode());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 校验并批量删除回款主表(逻辑删除),并级联逻辑删除其分款明细
|
|
|
|
|
*
|
|
|
|
|
* @param ids 待删除的主键集合
|
|
|
|
|
* @param isValid 是否校验流程状态与分款状态
|
|
|
|
|
* @return 是否删除成功
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
|
|
|
|
|