package com.by4cloud.platformx.business.service.impl;
|
|
import cn.hutool.core.bean.BeanUtil;
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.util.ObjUtil;
|
import cn.hutool.core.util.StrUtil;
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.by4cloud.platformx.business.dto.ContractPaymentScheduleProcessAddDTO;
|
import com.by4cloud.platformx.business.entity.*;
|
import com.by4cloud.platformx.business.mapper.*;
|
import com.by4cloud.platformx.business.service.ContractPaymentScheduleProcessService;
|
import com.by4cloud.platformx.business.vo.ContractPaymentScheduleVo;
|
import com.by4cloud.platformx.common.core.util.R;
|
import com.by4cloud.platformx.common.security.util.SecurityUtils;
|
import com.github.yulichang.wrapper.MPJLambdaWrapper;
|
import lombok.RequiredArgsConstructor;
|
import org.springframework.stereotype.Service;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
/**
|
* 履约节点
|
*
|
* @author syt
|
* @date 2026-05-11 11:10:26
|
*/
|
@Service
|
@RequiredArgsConstructor
|
public class ContractPaymentScheduleProcessServiceImpl extends ServiceImpl<ContractPaymentScheduleProcessMapper, ContractPaymentScheduleProcess> implements ContractPaymentScheduleProcessService {
|
|
private final ContractPaymentScheduleMapper contractPaymentScheduleMapper;
|
private final ContractMapper contractMapper;
|
private final ContractSubjectMatterMapper subjectMatterMapper;
|
private final PaymentConfirmMapper paymentConfirmMapper;
|
private final ContractOutBoundMapper contractOutBoundMapper;
|
|
@Override
|
public R add(ContractPaymentScheduleProcessAddDTO addDTO) {
|
ContractPaymentSchedule schedule = contractPaymentScheduleMapper.selectById(addDTO.getScheduleId());
|
if (ObjUtil.isNull(schedule)) {
|
return R.failed("履约阶段与合同不一致,请联系技术人员");
|
}
|
//合同
|
Contract contract = contractMapper.selectById(schedule.getContractId());
|
if (ObjUtil.isNull(contract)) {
|
return R.failed("合同信息异常");
|
}
|
return handleSchedule(addDTO, schedule, contract);
|
|
}
|
|
public void saveScheduleProcess(Date date, ContractPaymentSchedule schedule) {
|
//更新履约
|
ContractPaymentScheduleProcess contractPaymentScheduleProcess = new ContractPaymentScheduleProcess();
|
contractPaymentScheduleProcess.setContractId(schedule.getContractId());
|
contractPaymentScheduleProcess.setContractName(schedule.getContractName());
|
contractPaymentScheduleProcess.setScheduleId(schedule.getId());
|
contractPaymentScheduleProcess.setScheduleName(schedule.getStageName());
|
contractPaymentScheduleProcess.setProcessDate(date);
|
ContractPaymentScheduleProcess lastProcess = baseMapper.selectOne(Wrappers.<ContractPaymentScheduleProcess>lambdaQuery().eq(ContractPaymentScheduleProcess::getContractId, schedule.getContractId())
|
.eq(ContractPaymentScheduleProcess::getScheduleId, schedule.getId()).last("limit 1"));
|
if (ObjUtil.isNull(lastProcess)) {
|
baseMapper.insert(contractPaymentScheduleProcess);
|
}
|
}
|
|
private R handleSchedule(ContractPaymentScheduleProcessAddDTO addDTO, ContractPaymentSchedule schedule, Contract contract) {
|
if (schedule.getStageName().equals("货到签收")) {
|
if (CollUtil.isEmpty(addDTO.getContractOutBoundIds())) {
|
return R.failed("签收信息不能为空");
|
}
|
//更新合同出库到货时间
|
addDTO.getContractOutBoundIds().forEach(contractOutBoundId -> {
|
ContractOutBound contractOutBound = contractOutBoundMapper.selectById(contractOutBoundId);
|
contractOutBound.setArrivalTime(addDTO.getProcessDate());
|
contractOutBound.setArrivalAttNames(addDTO.getOutBoundAttNames());
|
contractOutBound.setArrivalAttPaths(addDTO.getOutBoundAttPaths());
|
contractOutBoundMapper.updateById(contractOutBound);
|
});
|
}
|
//付款比例不为0 保存收款明细
|
if (schedule.getPaymentRatio().compareTo(new BigDecimal("0")) > 0) {
|
savePaymentConfirm(addDTO, contract, schedule);
|
}
|
|
updateCurrentSchedule(addDTO.getProcessDate(), schedule, contract);
|
//保存履约记录
|
saveScheduleProcess(addDTO.getProcessDate(), schedule);
|
return R.ok();
|
}
|
|
private void savePaymentConfirm(ContractPaymentScheduleProcessAddDTO addDTO, Contract contract, ContractPaymentSchedule schedule) {
|
BigDecimal amount = schedule.getPlannedAmount();
|
if (schedule.getStageName().equals("货到签收")) {
|
amount = new BigDecimal("0");
|
//计算签收价格
|
for (Long contractOutBoundId : addDTO.getContractOutBoundIds()) {
|
ContractOutBound contractOutBound = contractOutBoundMapper.selectById(contractOutBoundId);
|
ContractSubjectMatter subjectMatter = subjectMatterMapper.selectOne(Wrappers.<ContractSubjectMatter>lambdaQuery()
|
.eq(ContractSubjectMatter::getContractId, contract.getId())
|
.eq(ContractSubjectMatter::getMaterialCode, contractOutBound.getSubjectMatterCode())
|
.eq(ContractSubjectMatter::getLineNo, contractOutBound.getLineNo())
|
.last("limit 1"));
|
amount = amount.add(contractOutBound.getOutBoundNum().multiply(subjectMatter.getUnitPrice()));
|
}
|
//实际到货金额按比例计算
|
amount = schedule.getPlannedAmount().multiply(amount.divide(contract.getAmount(), 2, RoundingMode.HALF_UP));
|
}
|
|
//新增当前阶段应收
|
PaymentConfirm currentConfim = new PaymentConfirm();
|
currentConfim.setBusinessType(schedule.getStageName() + "应收");
|
currentConfim.setBusGuestId(contract.getPartyAId());
|
currentConfim.setBusGuestName(contract.getPartyA());
|
currentConfim.setContractId(contract.getId());
|
currentConfim.setContractName(contract.getContractName());
|
currentConfim.setContractNo(contract.getContractNo());
|
currentConfim.setScheduleId(schedule.getId());
|
currentConfim.setScheduleName(schedule.getStageName());
|
currentConfim.setConfirmTime(addDTO.getProcessDate());
|
currentConfim.setTransationAmount(amount);
|
currentConfim.setReceivableAmount(amount);
|
PaymentConfirm lastConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId, contract.getId())
|
.orderByDesc(PaymentConfirm::getCreateTime).last("limit 1"));
|
if (ObjUtil.isNotNull(lastConfirm)) {
|
currentConfim.setTotalAmount(lastConfirm.getTotalAmount().subtract(currentConfim.getTransationAmount()));
|
if (contract.getContractNo().startsWith("ZB-")) {
|
paymentConfirmMapper.insert(currentConfim);
|
}
|
return;
|
}
|
currentConfim.setTotalAmount(currentConfim.getTransationAmount().multiply(new BigDecimal("-1")));
|
paymentConfirmMapper.insert(currentConfim);
|
handleBeforeRemain(currentConfim, contract);
|
}
|
|
public void handleBeforeRemain(PaymentConfirm currentConfim, Contract contract) {
|
//客户付款完成合同
|
List<Contract> customerCompleteContractList = contractMapper.selectList(Wrappers.<Contract>lambdaQuery().eq(Contract::getPartyAId, contract.getPartyAId())
|
.eq(Contract::getPartyBId, SecurityUtils.getUser().getCompId()).eq(Contract::getContractStatus, 3));
|
if (CollUtil.isNotEmpty(customerCompleteContractList)) {
|
List<BigDecimal> outAmountList = new ArrayList<>();
|
for (Contract completeContract : customerCompleteContractList) {
|
PaymentConfirm contractLastConfirm = paymentConfirmMapper.selectOne(Wrappers.<PaymentConfirm>lambdaQuery().eq(PaymentConfirm::getContractId, completeContract.getId())
|
.orderByDesc(PaymentConfirm::getCreateTime).last("limit 1"));
|
//查询客户付款完成合同中最后明细金额 有预收转入当前合同
|
if (contractLastConfirm.getTotalAmount().compareTo(new BigDecimal("0")) > 0 &&
|
contract.getContractNo().startsWith("ZB-")) {
|
//新增完成付款合同 资金转出
|
PaymentConfirm outConfirm = BeanUtil.copyProperties(contractLastConfirm, PaymentConfirm.class, "id", "transationAmount",
|
"advanceAmount", "receivableAmount", "overdueAmount", "totalAmount");
|
outConfirm.setBusinessType("资金转出");
|
outConfirm.setConfirmTime(new Date());
|
outConfirm.setTransationAmount(contractLastConfirm.getTotalAmount());
|
outConfirm.setTotalAmount(new BigDecimal("0"));
|
if (contract.getContractNo().startsWith("ZB-")) {
|
paymentConfirmMapper.insert(outConfirm);
|
}
|
outAmountList.add(contractLastConfirm.getTotalAmount());
|
}
|
}
|
if (CollUtil.isNotEmpty(outAmountList)) {
|
BigDecimal currentSum = outAmountList.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
//新增当前合同 资金转入
|
PaymentConfirm inConfirm = BeanUtil.copyProperties(currentConfim, PaymentConfirm.class, "id", "transationAmount",
|
"advanceAmount", "receivableAmount", "overdueAmount", "totalAmount");
|
inConfirm.setBusinessType("资金转入");
|
inConfirm.setConfirmTime(new Date());
|
inConfirm.setTransationAmount(currentSum);
|
inConfirm.setTotalAmount(currentConfim.getTotalAmount().add(currentSum));
|
if (inConfirm.getTotalAmount().compareTo(new BigDecimal("0")) > 0) {
|
inConfirm.setAdvanceAmount(inConfirm.getTotalAmount());
|
} else if (inConfirm.getTotalAmount().compareTo(new BigDecimal("0")) < 0) {
|
inConfirm.setReceivableAmount(inConfirm.getTotalAmount().multiply(new BigDecimal("-1")));
|
}
|
if (contract.getContractNo().startsWith("ZB-")) {
|
paymentConfirmMapper.insert(inConfirm);
|
}
|
contract.setPaidAmount(currentSum);
|
contractMapper.updateById(contract);
|
}
|
}
|
}
|
|
private void updateCurrentSchedule(Date date, ContractPaymentSchedule schedule, Contract contract) {
|
|
//查询是否有后续阶段
|
ContractPaymentSchedule afterOneSchedule = contractPaymentScheduleMapper.selectOne(Wrappers.<ContractPaymentSchedule>lambdaQuery()
|
.eq(ContractPaymentSchedule::getContractId, schedule.getContractId())
|
.gt(ContractPaymentSchedule::getStageOrder, schedule.getStageOrder())
|
.orderByAsc(ContractPaymentSchedule::getCreateTime)
|
.last("limit 1"));
|
if (ObjUtil.isNotNull(afterOneSchedule)) {
|
//更新下阶段名称
|
List<ContractOutBound> contractOutBoundList = contractOutBoundMapper.selectList(Wrappers.<ContractOutBound>lambdaQuery().eq(ContractOutBound::getContractId, contract.getId())
|
.isNull(ContractOutBound::getArrivalTime));
|
if (CollUtil.isEmpty(contractOutBoundList)) {
|
contract.setNextScheduleName(afterOneSchedule.getStageName());
|
}
|
}
|
if (ObjUtil.isNull(afterOneSchedule)) {
|
contract.setNextScheduleName("");
|
}
|
contractMapper.updateById(contract);
|
//更新履约阶段时间
|
if (ObjUtil.isNull(schedule.getEffectiveDate()) && ObjUtil.isNull(schedule.getEffectiveEndDate())) {
|
schedule.setEffectiveEndDate(DateUtil.offsetDay(date, schedule.getAgreedDays()));
|
}
|
contractPaymentScheduleMapper.updateById(schedule);
|
}
|
|
@Override
|
public R selectScheduleProcess(Long id) {
|
MPJLambdaWrapper<ContractPaymentSchedule> wrapper = new MPJLambdaWrapper<ContractPaymentSchedule>()
|
.select(ContractPaymentSchedule::getId, ContractPaymentSchedule::getStageName, ContractPaymentSchedule::getEffectiveDate,
|
ContractPaymentSchedule::getPlannedAmount, ContractPaymentSchedule::getPlannedAmount,
|
ContractPaymentSchedule::getEffectiveEndDate, ContractPaymentSchedule::getPaymentDate,
|
ContractPaymentSchedule::getPaymentStatus, ContractPaymentSchedule::getActualAmount,
|
ContractPaymentSchedule::getAgreedDays, ContractPaymentSchedule::getPaymentRatio)
|
.select(ContractPaymentScheduleProcess::getProcessDate)
|
.leftJoin(ContractPaymentScheduleProcess.class, ContractPaymentScheduleProcess::getScheduleId, ContractPaymentSchedule::getId)
|
.eq(ContractPaymentSchedule::getContractId, id)
|
.orderByAsc(ContractPaymentSchedule::getCreateTime);
|
List<ContractPaymentScheduleVo> scheduleVoList = contractPaymentScheduleMapper.selectJoinList(ContractPaymentScheduleVo.class, wrapper);
|
return R.ok(scheduleVoList);
|
}
|
}
|