|
|
|
|
@ -1,31 +1,50 @@
|
|
|
|
|
package org.dromara.oa.erp.service.impl;
|
|
|
|
|
|
|
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
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;
|
|
|
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
import com.github.yulichang.toolkit.JoinWrappers;
|
|
|
|
|
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;
|
|
|
|
|
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 com.github.yulichang.toolkit.JoinWrappers;
|
|
|
|
|
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
|
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
|
|
import lombok.RequiredArgsConstructor;
|
|
|
|
|
import org.dromara.oa.crm.domain.CrmShippingTariff;
|
|
|
|
|
import org.dromara.oa.crm.domain.bo.CrmShippingTariffBo;
|
|
|
|
|
import org.dromara.system.api.RemoteCodeRuleService;
|
|
|
|
|
import org.springframework.stereotype.Service;
|
|
|
|
|
import org.dromara.oa.erp.domain.bo.ErpFinAccountInstallmentBo;
|
|
|
|
|
import org.dromara.oa.erp.domain.vo.ErpFinAccountInstallmentVo;
|
|
|
|
|
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
|
|
|
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
|
|
|
import org.dromara.common.satoken.utils.LoginHelper;
|
|
|
|
|
import org.dromara.common.tenant.helper.TenantHelper;
|
|
|
|
|
import org.dromara.oa.erp.domain.ErpFinAccountInstallment;
|
|
|
|
|
import org.dromara.oa.erp.domain.ErpFinAccountInstallmentDetail;
|
|
|
|
|
import org.dromara.oa.erp.domain.bo.ErpFinAccountInstallmentBo;
|
|
|
|
|
import org.dromara.oa.erp.domain.bo.ErpFinAccountInstallmentDispatchBo;
|
|
|
|
|
import org.dromara.oa.erp.domain.vo.ErpFinAccountInstallmentVo;
|
|
|
|
|
import org.dromara.oa.erp.mapper.ErpFinAccountInstallmentDetailMapper;
|
|
|
|
|
import org.dromara.oa.erp.mapper.ErpFinAccountInstallmentMapper;
|
|
|
|
|
import org.dromara.oa.erp.service.IErpFinAccountInstallmentService;
|
|
|
|
|
import org.dromara.system.api.RemoteCodeRuleService;
|
|
|
|
|
import org.dromara.system.api.RemoteUserService;
|
|
|
|
|
import org.dromara.workflow.api.RemoteWorkflowService;
|
|
|
|
|
import org.dromara.workflow.api.domain.RemoteFlowInstanceBizExt;
|
|
|
|
|
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 java.math.BigDecimal;
|
|
|
|
|
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.Collection;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 分款信息Service业务层处理
|
|
|
|
|
@ -33,81 +52,139 @@ import java.util.Collection;
|
|
|
|
|
* @author xins
|
|
|
|
|
* @date 2026-03-09
|
|
|
|
|
*/
|
|
|
|
|
@Slf4j
|
|
|
|
|
@RequiredArgsConstructor
|
|
|
|
|
@Service
|
|
|
|
|
public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstallmentService {
|
|
|
|
|
|
|
|
|
|
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";
|
|
|
|
|
private static final String INSTALLMENT_STATUS_DISPATCHED = "1";
|
|
|
|
|
private static final String INSTALLMENT_STATUS_COMPLETE = "2";
|
|
|
|
|
|
|
|
|
|
private final ErpFinAccountInstallmentMapper baseMapper;
|
|
|
|
|
private final ErpFinAccountInstallmentDetailMapper detailMapper;
|
|
|
|
|
|
|
|
|
|
@DubboReference(timeout = 30000)
|
|
|
|
|
private RemoteCodeRuleService remoteCodeRuleService;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 查询分款信息
|
|
|
|
|
*
|
|
|
|
|
* @param accountInstallmentId 主键
|
|
|
|
|
* @return 分款信息
|
|
|
|
|
*/
|
|
|
|
|
@DubboReference
|
|
|
|
|
private RemoteUserService remoteUserService;
|
|
|
|
|
|
|
|
|
|
@DubboReference
|
|
|
|
|
private RemoteWorkflowService remoteWorkflowService;
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public ErpFinAccountInstallmentVo queryById(Long accountInstallmentId){
|
|
|
|
|
return baseMapper.selectVoById(accountInstallmentId);
|
|
|
|
|
public ErpFinAccountInstallmentVo queryById(Long accountInstallmentId) {
|
|
|
|
|
ErpFinAccountInstallmentVo vo = baseMapper.selectVoById(accountInstallmentId);
|
|
|
|
|
if (vo != null) {
|
|
|
|
|
fillManagerInfo(List.of(vo));
|
|
|
|
|
}
|
|
|
|
|
return vo;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 分页查询分款信息列表
|
|
|
|
|
*
|
|
|
|
|
* @param bo 查询条件
|
|
|
|
|
* @param pageQuery 分页参数
|
|
|
|
|
* @return 分款信息分页列表
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public TableDataInfo<ErpFinAccountInstallmentVo> queryPageList(ErpFinAccountInstallmentBo bo, PageQuery pageQuery) {
|
|
|
|
|
MPJLambdaWrapper<ErpFinAccountInstallment> lqw = buildQueryWrapper(bo);
|
|
|
|
|
Page<ErpFinAccountInstallmentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
|
|
|
|
return TableDataInfo.build(result);
|
|
|
|
|
}
|
|
|
|
|
@Override
|
|
|
|
|
public TableDataInfo<ErpFinAccountInstallmentVo> queryPageList(ErpFinAccountInstallmentBo bo, PageQuery pageQuery) {
|
|
|
|
|
MPJLambdaWrapper<ErpFinAccountInstallment> lqw = buildQueryWrapper(bo);
|
|
|
|
|
Page<ErpFinAccountInstallmentVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
|
|
|
|
fillManagerInfo(result.getRecords());
|
|
|
|
|
return TableDataInfo.build(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 查询符合条件的分款信息列表
|
|
|
|
|
*
|
|
|
|
|
* @param bo 查询条件
|
|
|
|
|
* @return 分款信息列表
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public List<ErpFinAccountInstallmentVo> queryList(ErpFinAccountInstallmentBo bo) {
|
|
|
|
|
MPJLambdaWrapper<ErpFinAccountInstallment> lqw = buildQueryWrapper(bo);
|
|
|
|
|
return baseMapper.selectVoList(lqw);
|
|
|
|
|
List<ErpFinAccountInstallmentVo> list = baseMapper.selectVoList(lqw);
|
|
|
|
|
fillManagerInfo(list);
|
|
|
|
|
return list;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private MPJLambdaWrapper<ErpFinAccountInstallment> buildQueryWrapper(ErpFinAccountInstallmentBo bo) {
|
|
|
|
|
Map<String, Object> params = bo.getParams();
|
|
|
|
|
MPJLambdaWrapper<ErpFinAccountInstallment> lqw = JoinWrappers.lambda(ErpFinAccountInstallment.class)
|
|
|
|
|
.selectAll(ErpFinAccountInstallment.class)
|
|
|
|
|
.eq(StringUtils.isNotBlank(bo.getInstallmentCode()), ErpFinAccountInstallment::getInstallmentCode, bo.getInstallmentCode())
|
|
|
|
|
.eq(bo.getCustomerId() != null, ErpFinAccountInstallment::getCustomerId, bo.getCustomerId())
|
|
|
|
|
.like(StringUtils.isNotBlank(bo.getCustomerName()), ErpFinAccountInstallment::getCustomerName, bo.getCustomerName())
|
|
|
|
|
.eq(StringUtils.isNotBlank(bo.getCurrency()), ErpFinAccountInstallment::getCurrency, bo.getCurrency())
|
|
|
|
|
.eq(bo.getPaymentAmount() != null, ErpFinAccountInstallment::getPaymentAmount, bo.getPaymentAmount())
|
|
|
|
|
.eq(bo.getPaymentDate() != null, ErpFinAccountInstallment::getPaymentDate, bo.getPaymentDate())
|
|
|
|
|
.eq(StringUtils.isNotBlank(bo.getInstallmentStatus()), ErpFinAccountInstallment::getInstallmentStatus, bo.getInstallmentStatus())
|
|
|
|
|
.eq(bo.getAccountManageId() != null, ErpFinAccountInstallment::getAccountManageId, bo.getAccountManageId())
|
|
|
|
|
.orderByAsc(ErpFinAccountInstallment::getInstallmentStatus)
|
|
|
|
|
.orderByDesc(ErpFinAccountInstallment::getCreateTime)
|
|
|
|
|
;
|
|
|
|
|
.selectAll(ErpFinAccountInstallment.class)
|
|
|
|
|
.eq(StringUtils.isNotBlank(bo.getInstallmentCode()), ErpFinAccountInstallment::getInstallmentCode, bo.getInstallmentCode())
|
|
|
|
|
.eq(bo.getCustomerId() != null, ErpFinAccountInstallment::getCustomerId, bo.getCustomerId())
|
|
|
|
|
.like(StringUtils.isNotBlank(bo.getCustomerName()), ErpFinAccountInstallment::getCustomerName, bo.getCustomerName())
|
|
|
|
|
.eq(StringUtils.isNotBlank(bo.getCurrency()), ErpFinAccountInstallment::getCurrency, bo.getCurrency())
|
|
|
|
|
.eq(bo.getPaymentAmount() != null, ErpFinAccountInstallment::getPaymentAmount, bo.getPaymentAmount())
|
|
|
|
|
.eq(bo.getPaymentDate() != null, ErpFinAccountInstallment::getPaymentDate, bo.getPaymentDate())
|
|
|
|
|
.eq(StringUtils.isNotBlank(bo.getFlowStatus()), ErpFinAccountInstallment::getFlowStatus, bo.getFlowStatus())
|
|
|
|
|
.eq(StringUtils.isNotBlank(bo.getInstallmentStatus()), ErpFinAccountInstallment::getInstallmentStatus, bo.getInstallmentStatus())
|
|
|
|
|
.orderByDesc(ErpFinAccountInstallment::getInstallmentCode)
|
|
|
|
|
.orderByDesc(ErpFinAccountInstallment::getCreateTime);
|
|
|
|
|
return lqw;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 新增分款信息
|
|
|
|
|
*
|
|
|
|
|
* @param bo 分款信息
|
|
|
|
|
* @return 是否新增成功
|
|
|
|
|
*/
|
|
|
|
|
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);
|
|
|
|
|
if (CollUtil.isNotEmpty(userIds)) {
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static String joinManagerUserIds(List<Long> ids) {
|
|
|
|
|
if (CollUtil.isEmpty(ids)) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
return ids.stream().map(String::valueOf).collect(Collectors.joining(","));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static List<Long> parseManagerUserIds(String idsStr) {
|
|
|
|
|
if (StringUtils.isBlank(idsStr)) {
|
|
|
|
|
return List.of();
|
|
|
|
|
}
|
|
|
|
|
return Arrays.stream(idsStr.split(","))
|
|
|
|
|
.map(String::trim)
|
|
|
|
|
.filter(StringUtils::isNotBlank)
|
|
|
|
|
.map(Long::valueOf)
|
|
|
|
|
.toList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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);
|
|
|
|
|
}
|
|
|
|
|
validEntityBeforeSave(add);
|
|
|
|
|
boolean flag = baseMapper.insert(add) > 0;
|
|
|
|
|
if (flag) {
|
|
|
|
|
@ -116,18 +193,10 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
return flag;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 新增分款信息
|
|
|
|
|
*
|
|
|
|
|
* @param installmentVolist 回款信息列表
|
|
|
|
|
* @return 是否新增成功
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public String importInstallmentData(List<ErpFinAccountInstallmentVo> installmentVolist) {
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (StringUtils.isNull(installmentVolist) || installmentVolist.isEmpty())
|
|
|
|
|
{
|
|
|
|
|
try {
|
|
|
|
|
if (StringUtils.isNull(installmentVolist) || installmentVolist.isEmpty()) {
|
|
|
|
|
throw new ServiceException("导入数据不能为空!");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -141,80 +210,293 @@ public class ErpFinAccountInstallmentServiceImpl implements IErpFinAccountInstal
|
|
|
|
|
StringBuilder successMsg = new StringBuilder();
|
|
|
|
|
StringBuilder failureMsg = new StringBuilder();
|
|
|
|
|
|
|
|
|
|
for (ErpFinAccountInstallmentVo installmentVo : installmentVolist)
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
// 检查必填字段
|
|
|
|
|
if (StringUtils.isEmpty(installmentVo.getCustomerName()) || installmentVo.getPaymentAmount() == null || installmentVo.getPaymentDate() == null)
|
|
|
|
|
{
|
|
|
|
|
for (ErpFinAccountInstallmentVo installmentVo : installmentVolist) {
|
|
|
|
|
try {
|
|
|
|
|
if (StringUtils.isEmpty(installmentVo.getCustomerName())
|
|
|
|
|
|| installmentVo.getPaymentAmount() == null
|
|
|
|
|
|| installmentVo.getPaymentDate() == null) {
|
|
|
|
|
failureNum++;
|
|
|
|
|
failureMsg.append("<br/>第" + (failureNum + 1) + "行数据不完整,缺少必填字段");
|
|
|
|
|
failureMsg.append("<br/>第").append(failureNum).append("行数据不完整,缺少必填字段");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ErpFinAccountInstallment add = MapstructUtils.convert(installmentVo, ErpFinAccountInstallment.class);
|
|
|
|
|
add.setInstallmentCode(code);
|
|
|
|
|
add.setFlowStatus(BusinessStatusEnum.DRAFT.getStatus());
|
|
|
|
|
add.setInstallmentStatus(INSTALLMENT_STATUS_NOT_ALLOCATED);
|
|
|
|
|
add.setDelFlag("0");
|
|
|
|
|
baseMapper.insert(add);
|
|
|
|
|
successNum++;
|
|
|
|
|
successMsg.append("<br/>" + successNum + "、" + installmentVo.getCustomerName() + " 导入成功");
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
successMsg.append("<br/>").append(successNum).append("、").append(installmentVo.getCustomerName()).append(" 导入成功");
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
failureNum++;
|
|
|
|
|
String msg = "<br/>" + installmentVo.getCustomerName() + " 导入失败:";
|
|
|
|
|
failureMsg.append(msg + e.getMessage());
|
|
|
|
|
failureMsg.append("<br/>").append(installmentVo.getCustomerName()).append(" 导入失败:").append(e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (failureNum > 0)
|
|
|
|
|
{
|
|
|
|
|
if (failureNum > 0) {
|
|
|
|
|
failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
|
|
|
|
|
throw new ServiceException(failureMsg.toString());
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
|
|
|
|
}
|
|
|
|
|
successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
|
|
|
|
|
return successMsg.toString();
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
} catch (ServiceException e) {
|
|
|
|
|
throw e;
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
throw new ServiceException("导入Excel数据失败:" + e.getMessage());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 修改分款信息
|
|
|
|
|
*
|
|
|
|
|
* @param bo 分款信息
|
|
|
|
|
* @return 是否修改成功
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public Boolean updateByBo(ErpFinAccountInstallmentBo bo) {
|
|
|
|
|
ErpFinAccountInstallment existing = baseMapper.selectById(bo.getAccountInstallmentId());
|
|
|
|
|
if (existing == null) {
|
|
|
|
|
throw new ServiceException("回款记录不存在");
|
|
|
|
|
}
|
|
|
|
|
if (!isFlowEditable(existing.getFlowStatus())) {
|
|
|
|
|
throw new ServiceException("仅流程草稿/退回/撤销状态的回款可修改");
|
|
|
|
|
}
|
|
|
|
|
if (!isInstallmentNotAllocated(existing.getInstallmentStatus())) {
|
|
|
|
|
throw new ServiceException("仅未分款的回款可修改");
|
|
|
|
|
}
|
|
|
|
|
ErpFinAccountInstallment update = MapstructUtils.convert(bo, ErpFinAccountInstallment.class);
|
|
|
|
|
validEntityBeforeSave(update);
|
|
|
|
|
return baseMapper.updateById(update) > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 保存前的数据校验
|
|
|
|
|
*/
|
|
|
|
|
private void validEntityBeforeSave(ErpFinAccountInstallment entity){
|
|
|
|
|
//TODO 做一些数据校验,如唯一约束
|
|
|
|
|
@Override
|
|
|
|
|
@GlobalTransactional(rollbackFor = Exception.class)
|
|
|
|
|
public Boolean dispatchToManagers(ErpFinAccountInstallmentDispatchBo bo) {
|
|
|
|
|
List<Long> installmentIds = bo.getAccountInstallmentIds().stream().distinct().toList();
|
|
|
|
|
List<Long> managerUserIds = bo.getManagerUserIds().stream().distinct().toList();
|
|
|
|
|
if (CollUtil.isEmpty(installmentIds) || CollUtil.isEmpty(managerUserIds)) {
|
|
|
|
|
throw new ServiceException("请选择回款记录与客户经理");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<ErpFinAccountInstallment> installments = baseMapper.selectBatchIds(installmentIds);
|
|
|
|
|
if (installments.size() != installmentIds.size()) {
|
|
|
|
|
throw new ServiceException("部分回款记录不存在");
|
|
|
|
|
}
|
|
|
|
|
for (ErpFinAccountInstallment inst : installments) {
|
|
|
|
|
if (!isFlowEditable(inst.getFlowStatus())) {
|
|
|
|
|
throw new ServiceException("回款【" + inst.getCustomerName() + "】流程状态不允许派发");
|
|
|
|
|
}
|
|
|
|
|
if (!isInstallmentNotAllocated(inst.getInstallmentStatus())) {
|
|
|
|
|
throw new ServiceException("回款【" + inst.getCustomerName() + "】已派发,无法重复派发");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Long dispatchUserId = LoginHelper.getUserId();
|
|
|
|
|
Long dispatchDeptId = LoginHelper.getDeptId();
|
|
|
|
|
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) {
|
|
|
|
|
ErpFinAccountInstallment update = new ErpFinAccountInstallment();
|
|
|
|
|
update.setAccountInstallmentId(installmentId);
|
|
|
|
|
update.setAccountManagerIds(accountManagerIds);
|
|
|
|
|
update.setFlowStatus(BusinessStatusEnum.WAITING.getStatus());
|
|
|
|
|
update.setInstallmentStatus(INSTALLMENT_STATUS_DISPATCHED);
|
|
|
|
|
update.setDispatchUserId(dispatchUserId);
|
|
|
|
|
update.setDispatchDeptId(dispatchDeptId);
|
|
|
|
|
update.setDispatchDate(now);
|
|
|
|
|
baseMapper.updateById(update);
|
|
|
|
|
|
|
|
|
|
ErpFinAccountInstallment inst = installmentMap.get(installmentId);
|
|
|
|
|
startDispatchFlow(installmentId, inst, bo);
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 校验并批量删除分款信息信息
|
|
|
|
|
*
|
|
|
|
|
* @param ids 待删除的主键集合
|
|
|
|
|
* @param isValid 是否进行有效性校验
|
|
|
|
|
* @return 是否删除成功
|
|
|
|
|
* 派发后发起分款审核流程(流程参数由前端组装传入)
|
|
|
|
|
*/
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RemoteStartProcess startProcess = new RemoteStartProcess();
|
|
|
|
|
startProcess.setBusinessId(installmentId.toString());
|
|
|
|
|
startProcess.setFlowCode(StringUtils.isNotBlank(bo.getFlowCode()) ? bo.getFlowCode() : FLOW_CODE_FKSH);
|
|
|
|
|
startProcess.setVariables(variables);
|
|
|
|
|
|
|
|
|
|
RemoteFlowInstanceBizExt bizExt = resolveDispatchBizExt(installmentId, inst, bo);
|
|
|
|
|
bizExt.setBusinessId(startProcess.getBusinessId());
|
|
|
|
|
startProcess.setBizExt(bizExt);
|
|
|
|
|
|
|
|
|
|
boolean started = remoteWorkflowService.startCompleteTask(startProcess);
|
|
|
|
|
if (!started) {
|
|
|
|
|
throw new ServiceException("分款审核流程发起失败");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
RemoteFlowInstanceBizExt bizExt = new RemoteFlowInstanceBizExt();
|
|
|
|
|
if (inst != null) {
|
|
|
|
|
bizExt.setBusinessCode(inst.getInstallmentCode());
|
|
|
|
|
bizExt.setBusinessTitle("分款审核-" + inst.getCustomerName());
|
|
|
|
|
} else {
|
|
|
|
|
bizExt.setBusinessTitle("分款审核");
|
|
|
|
|
}
|
|
|
|
|
return bizExt;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 分款审核流程状态监听
|
|
|
|
|
*/
|
|
|
|
|
@EventListener(condition = "#processEvent.flowCode == 'FKSH'")
|
|
|
|
|
public void processHandler(ProcessEvent processEvent) {
|
|
|
|
|
TenantHelper.dynamic(processEvent.getTenantId(), () -> {
|
|
|
|
|
log.info("【分款审核流程监听】flowCode={}, status={}", processEvent.getFlowCode(), processEvent.getStatus());
|
|
|
|
|
|
|
|
|
|
Long installmentId = Convert.toLong(processEvent.getBusinessId());
|
|
|
|
|
ErpFinAccountInstallment inst = baseMapper.selectById(installmentId);
|
|
|
|
|
if (inst == null) {
|
|
|
|
|
log.error("未找到回款分款记录,id={}", installmentId);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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("您不是该回款的指定客户经理,无法进行分款操作");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 流程是否可编辑/派发(同出差申请:草稿、退回、撤销) */
|
|
|
|
|
private static boolean isFlowEditable(String flowStatus) {
|
|
|
|
|
return BusinessStatusEnum.isDraftOrCancelOrBack(flowStatus);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** 分款状态:未分款(installment_status = 0) */
|
|
|
|
|
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) {
|
|
|
|
|
// 预留业务校验
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 删除回款主表(逻辑删除),并级联逻辑删除其分款明细
|
|
|
|
|
*/
|
|
|
|
|
@Override
|
|
|
|
|
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
|
|
|
|
|
if(isValid){
|
|
|
|
|
//TODO 做一些业务上的校验,判断是否需要校验
|
|
|
|
|
if (isValid) {
|
|
|
|
|
List<ErpFinAccountInstallment> list = baseMapper.selectBatchIds(ids);
|
|
|
|
|
for (ErpFinAccountInstallment item : list) {
|
|
|
|
|
if (!isFlowEditable(item.getFlowStatus())) {
|
|
|
|
|
throw new ServiceException("仅可删除流程草稿/退回/撤销状态的回款记录");
|
|
|
|
|
}
|
|
|
|
|
if (!isInstallmentNotAllocated(item.getInstallmentStatus())) {
|
|
|
|
|
throw new ServiceException("仅可删除未分款的回款记录");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (CollUtil.isNotEmpty(ids)) {
|
|
|
|
|
detailMapper.delete(Wrappers.lambdaQuery(ErpFinAccountInstallmentDetail.class)
|
|
|
|
|
.in(ErpFinAccountInstallmentDetail::getAccountInstallmentId, ids));
|
|
|
|
|
}
|
|
|
|
|
return baseMapper.deleteByIds(ids) > 0;
|
|
|
|
|
}
|
|
|
|
|
|