package com.by4cloud.platformx.business.service.impl; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ArrayUtil; 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.api.feign.RemoteFlowProcessService; import com.by4cloud.platformx.business.constant.FlowNameEnum; import com.by4cloud.platformx.business.dto.ContractAddDTO; import com.by4cloud.platformx.business.dto.ContractUpdateDTO; import com.by4cloud.platformx.business.entity.*; import com.by4cloud.platformx.business.mapper.*; import com.by4cloud.platformx.business.service.ContractService; import com.by4cloud.platformx.business.utils.ContractNumberGenerator; import com.by4cloud.platformx.business.vo.ContractDetailVo; import com.by4cloud.platformx.common.core.util.R; import com.by4cloud.platformx.common.security.util.SecurityUtils; import com.by4cloud.platformx.flow.task.api.feign.RemoteBusinessService; import com.by4cloud.platformx.flow.task.dto.ProcessInstanceParamDto; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.io.Serializable; import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; /** * @author cd * @description * @date 2026/4/29 14:07 **/ @Service @RequiredArgsConstructor public class ContractServiceImpl extends ServiceImpl implements ContractService { private final ContractSubjectMatterMapper contractSubjectMatterMapper; private final ContractPaymentScheduleMapper contractPaymentScheduleMapper; private final ContractPaymentScheduleProcessMapper contractPaymentScheduleProcessMapper; private final PaymentConfirmMapper paymentConfirmMapper; private final CurrentOverdueMapper currentOverdueMapper; private final RemoteFlowProcessService remoteFlowProcessService; @Override public R add(ContractAddDTO addDTO) { Contract contract = BeanUtil.copyProperties(addDTO,Contract.class); contract.setPartyBId(SecurityUtils.getUser().getCompId()); contract.setPartyB(SecurityUtils.getUser().getCompName()); contract.setContractNo(ContractNumberGenerator.generateContractNumber()); contract.setBillingStatus("0"); contract.setErpPushFlag("0"); List contracts; contracts = baseMapper.selectList(Wrappers.lambdaQuery().eq(Contract::getContractNo,contract.getContractNo())); while (ArrayUtil.isNotEmpty(contracts.toArray())){ contract.setContractNo(ContractNumberGenerator.generateContractNumber()); contracts = baseMapper.selectList(Wrappers.lambdaQuery().eq(Contract::getContractNo,contract.getContractNo())); } baseMapper.insert(contract); if (ArrayUtil.isNotEmpty(addDTO.getContractSubjectMatter())){ addDTO.getContractSubjectMatter().stream().forEach(contractSubjectMatterAddDTO -> { ContractSubjectMatter subjectMatter = BeanUtil.copyProperties(contractSubjectMatterAddDTO, ContractSubjectMatter.class); subjectMatter.setContractId(contract.getId()); subjectMatter.setContractName(contract.getContractName()); subjectMatter.setDeliveredQuantity(new BigDecimal("0")); subjectMatter.setDeliveryStatus(0); subjectMatter.setTotalAmount(contractSubjectMatterAddDTO.getQuantity().multiply(contractSubjectMatterAddDTO.getUnitPrice())); contractSubjectMatterMapper.insert(subjectMatter); }); } if (ArrayUtil.isNotEmpty(addDTO.getContractPaymentSchedule())){ AtomicInteger index = new AtomicInteger(1); addDTO.getContractPaymentSchedule().stream().forEach(contractPaymentScheduleAddDTO -> { int currentIndex = index.getAndIncrement(); ContractPaymentSchedule schedule = BeanUtil.copyProperties(contractPaymentScheduleAddDTO, ContractPaymentSchedule.class); if (contractPaymentScheduleAddDTO.getStageName().equals("合同签订")){ schedule.setEffectiveDate(DateUtil.offsetDay(contract.getSignDate(),contractPaymentScheduleAddDTO.getAgreedDays())); } if (ObjUtil.isNotNull(schedule.getEffectiveDate())) { if (schedule.getEffectiveDate().before(DateUtil.date())) { schedule.setFulfillmentStatus(1); } else { schedule.setFulfillmentStatus(0); } } schedule.setPaymentStatus(0); schedule.setContractId(contract.getId()); schedule.setContractName(contract.getContractName()); schedule.setPlannedAmount(contract.getAmount().multiply(schedule.getPaymentRatio().divide(new BigDecimal("100")))); schedule.setStageOrder(currentIndex); contractPaymentScheduleMapper.insert(schedule); if (contractPaymentScheduleAddDTO.getStageName().equals("货到签收")){ contract.setArrivalScheduleId(schedule.getId()); baseMapper.updateById(contract); } if (contractPaymentScheduleAddDTO.getStageName().equals("调试完成或验收")){ contract.setAcceptScheduleId(schedule.getId()); baseMapper.updateById(contract); } }); } return R.ok(); } @Override public R edit(ContractUpdateDTO updateDTO) { Contract entity = baseMapper.selectById(updateDTO.getId()); if (!StrUtil.equals(entity.getContractStatus()+"","0")){ return R.failed("当前状态无法修改合同"); } Contract contract = BeanUtil.copyProperties(updateDTO,Contract.class); contract.setContractNo(ContractNumberGenerator.generateContractNumber()); contract.setBillingStatus("0"); contract.setErpPushFlag("0"); List contracts; contracts = baseMapper.selectList(Wrappers.lambdaQuery().eq(Contract::getContractNo,contract.getContractNo())); while (ArrayUtil.isNotEmpty(contracts.toArray())){ contract.setContractNo(ContractNumberGenerator.generateContractNumber()); contracts = baseMapper.selectList(Wrappers.lambdaQuery().eq(Contract::getContractNo,contract.getContractNo())); } baseMapper.updateById(contract); if (ArrayUtil.isNotEmpty(updateDTO.getContractSubjectMatter())){ contractSubjectMatterMapper.delete(Wrappers.lambdaQuery().eq(ContractSubjectMatter::getContractId,contract.getId())); updateDTO.getContractSubjectMatter().stream().forEach(contractSubjectMatterAddDTO -> { ContractSubjectMatter subjectMatter = BeanUtil.copyProperties(contractSubjectMatterAddDTO, ContractSubjectMatter.class); subjectMatter.setContractId(contract.getId()); subjectMatter.setContractName(contract.getContractName()); subjectMatter.setDeliveredQuantity(new BigDecimal("0")); subjectMatter.setDeliveryStatus(0); contractSubjectMatterMapper.insert(subjectMatter); }); } if (ArrayUtil.isNotEmpty(updateDTO.getContractPaymentSchedule())){ contractPaymentScheduleMapper.delete(Wrappers.lambdaQuery().eq(ContractPaymentSchedule::getContractId,contract.getId())); AtomicInteger index = new AtomicInteger(1); updateDTO.getContractPaymentSchedule().stream().forEach(contractPaymentScheduleAddDTO -> { int currentIndex = index.getAndIncrement(); ContractPaymentSchedule schedule = BeanUtil.copyProperties(contractPaymentScheduleAddDTO, ContractPaymentSchedule.class); schedule.setContractId(contract.getId()); schedule.setContractName(contract.getContractName()); schedule.setPlannedAmount(contract.getAmount().multiply(schedule.getPaymentRatio().divide(new BigDecimal("100")))); schedule.setStageOrder(currentIndex); contractPaymentScheduleMapper.insert(schedule); if (contractPaymentScheduleAddDTO.getStageName().equals("货到签收")){ contract.setArrivalScheduleId(schedule.getId()); baseMapper.updateById(contract); } if (contractPaymentScheduleAddDTO.getStageName().equals("调试完成或验收")){ contract.setAcceptScheduleId(schedule.getId()); baseMapper.updateById(contract); } }); } return R.ok(); } @Override public ContractDetailVo detail(Long id) { Contract contract = baseMapper.selectById(id); ContractDetailVo detailVo = BeanUtil.copyProperties(contract,ContractDetailVo.class); List subjectMatterList = contractSubjectMatterMapper.selectList(Wrappers.lambdaQuery().eq(ContractSubjectMatter::getContractId,id)); detailVo.setContractSubjectMatter(subjectMatterList); List paymentScheduleList = contractPaymentScheduleMapper.selectList(Wrappers.lambdaQuery().eq(ContractPaymentSchedule::getContractId,contract.getId())); detailVo.setContractPaymentSchedule(paymentScheduleList); return detailVo; } @Override public R startApproval(Long id) { Contract contract = baseMapper.selectById(id); //启动流程 ProcessInstanceParamDto dto = new ProcessInstanceParamDto(); Map map = BeanUtil.beanToMap(contract); dto.setParamMap(map); dto.setFlowName(FlowNameEnum.合同审批.name()); R r1 = remoteFlowProcessService.startProcessInstance(dto); if (r1.getCode() == 1) { return R.failed("流程启动失败"); } contract.setContractStatus(2); baseMapper.updateById(contract); return R.ok(); } public void takeEffect(Long id) { Contract contract = baseMapper.selectById(id); contract.setContractStatus(1); baseMapper.updateById(contract); ContractPaymentSchedule fitstSchedule = contractPaymentScheduleMapper.selectOne(Wrappers.lambdaQuery().eq(ContractPaymentSchedule::getContractId,contract.getId()) .orderByAsc(ContractPaymentSchedule::getCreateTime).last("limit 1")); if (fitstSchedule.getStageName().equals("合同签订")){ //新增应收 PaymentConfirm paymentConfirm = new PaymentConfirm(); paymentConfirm.setBusinessType("合同签订应收"); paymentConfirm.setBusGuestId(contract.getPartyAId()); paymentConfirm.setBusGuestName(contract.getPartyA()); paymentConfirm.setContractId(contract.getId()); paymentConfirm.setContractName(contract.getContractName()); paymentConfirm.setContractNo(contract.getContractNo()); paymentConfirm.setScheduleId(fitstSchedule.getId()); paymentConfirm.setScheduleName(fitstSchedule.getStageName()); paymentConfirm.setConfirmTime(new Date()); paymentConfirm.setTransationAmount(fitstSchedule.getPlannedAmount()); paymentConfirm.setReceivableAmount(fitstSchedule.getPlannedAmount()); paymentConfirm.setTotalAmount(fitstSchedule.getPlannedAmount().multiply(new BigDecimal("-1"))); PaymentConfirm lastNewConfirm = paymentConfirmMapper.selectOne(Wrappers.lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); BigDecimal lastNewTotal = new BigDecimal("0"); if(ObjUtil.isNotNull(lastNewConfirm)){ lastNewTotal = lastNewConfirm.getTotalAmount(); } paymentConfirm.setTotalAmount(lastNewTotal.subtract(paymentConfirm.getReceivableAmount())); paymentConfirmMapper.insert(paymentConfirm); //新增合同履约记录 ContractPaymentScheduleProcess process = new ContractPaymentScheduleProcess(); process.setContractId(contract.getId()); process.setContractName(contract.getContractName()); process.setScheduleId(fitstSchedule.getId()); process.setScheduleName(fitstSchedule.getStageName()); process.setProcessDate(contract.getSignDate()); contractPaymentScheduleProcessMapper.insert(process); //当前为合同最后阶段 PaymentConfirm newConfirm = paymentConfirmMapper.selectOne(Wrappers.lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); if (newConfirm.getTotalAmount().compareTo(new BigDecimal("0"))>=0){ //有预付且超过应收 关闭合同状态 contract.setContractStatus(3); baseMapper.updateById(contract); } }else if (fitstSchedule.getStageName().equals("发货前")) { //更新合同下个阶段 contract.setNextScheduleName("无"); baseMapper.updateById(contract); }else if (fitstSchedule.getStageName().equals("货到签收")) { //更新合同下个阶段 contract.setNextScheduleName("货到签收"); baseMapper.updateById(contract); }else if (fitstSchedule.getStageName().equals("调试完成或验收")) { //更新合同下个阶段 contract.setNextScheduleName("调试完成或验收"); baseMapper.updateById(contract); }else { //新增应收 PaymentConfirm paymentConfirm = new PaymentConfirm(); paymentConfirm.setBusinessType("质保金"); paymentConfirm.setBusGuestId(contract.getPartyAId()); paymentConfirm.setBusGuestName(contract.getPartyA()); paymentConfirm.setContractId(contract.getId()); paymentConfirm.setContractName(contract.getContractName()); paymentConfirm.setContractNo(contract.getContractNo()); paymentConfirm.setScheduleId(fitstSchedule.getId()); paymentConfirm.setScheduleName(fitstSchedule.getStageName()); paymentConfirm.setConfirmTime(new Date()); paymentConfirm.setTransationAmount(fitstSchedule.getPlannedAmount()); paymentConfirm.setReceivableAmount(fitstSchedule.getPlannedAmount()); paymentConfirm.setTotalAmount(fitstSchedule.getPlannedAmount().multiply(new BigDecimal("-1"))); PaymentConfirm lastNewConfirm = paymentConfirmMapper.selectOne(Wrappers.lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); BigDecimal lastNewTotal = new BigDecimal("0"); if(ObjUtil.isNotNull(lastNewConfirm)){ lastNewTotal = lastNewConfirm.getTotalAmount(); } paymentConfirm.setTotalAmount(lastNewTotal.subtract(paymentConfirm.getReceivableAmount())); paymentConfirmMapper.insert(paymentConfirm); } //查询是否有后续阶段 List afterSchedule = contractPaymentScheduleMapper.selectList(Wrappers.lambdaQuery() .eq(ContractPaymentSchedule::getContractId, fitstSchedule.getContractId()) .gt(ContractPaymentSchedule::getStageOrder, fitstSchedule.getStageOrder()) .orderByAsc(ContractPaymentSchedule::getCreateTime)); if (ArrayUtil.isNotEmpty(afterSchedule.toArray())&&afterSchedule.size()==1){ //最后阶段生效时间 ContractPaymentSchedule endSchedule = afterSchedule.get(0); if (StrUtil.equals(endSchedule.getStageName(),"质保金")){ endSchedule.setEffectiveDate(DateUtil.offsetDay(new Date(),endSchedule.getAgreedDays())); endSchedule.setEffectiveEndDate(contract.getExpirationDate()); contractPaymentScheduleMapper.updateById(endSchedule); //第一阶段生效时间 fitstSchedule.setEffectiveDate(DateUtil.offsetDay(contract.getSignDate(),fitstSchedule.getAgreedDays())); fitstSchedule.setEffectiveEndDate(endSchedule.getEffectiveDate()); contractPaymentScheduleMapper.updateById(fitstSchedule); //最后阶段应收 PaymentConfirm newConfim = new PaymentConfirm(); newConfim.setBusinessType(endSchedule.getStageName()+"应收"); newConfim.setBusGuestId(contract.getPartyAId()); newConfim.setBusGuestName(contract.getPartyA()); newConfim.setContractId(contract.getId()); newConfim.setContractName(contract.getContractName()); newConfim.setContractNo(contract.getContractNo()); newConfim.setScheduleId(endSchedule.getId()); newConfim.setScheduleName(endSchedule.getStageName()); newConfim.setConfirmTime(new Date()); newConfim.setTransationAmount(endSchedule.getPlannedAmount()); newConfim.setReceivableAmount(endSchedule.getPlannedAmount()); PaymentConfirm lastNewConfirm = paymentConfirmMapper.selectOne(Wrappers.lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); BigDecimal lastNewTotal = new BigDecimal("0"); if(ObjUtil.isNotNull(lastNewConfirm)){ lastNewTotal = lastNewConfirm.getTotalAmount(); } newConfim.setTotalAmount(lastNewTotal.subtract(newConfim.getReceivableAmount())); paymentConfirmMapper.insert(newConfim); } //更新合同下个阶段 contract.setNextScheduleName(endSchedule.getStageName()); baseMapper.updateById(contract); } if(ArrayUtil.isNotEmpty(afterSchedule.toArray())&&afterSchedule.size()>1){ //第一阶段生效时间 fitstSchedule.setEffectiveDate(DateUtil.offsetDay(contract.getSignDate(),fitstSchedule.getAgreedDays())); contractPaymentScheduleMapper.updateById(fitstSchedule); //更新合同下个阶段 contract.setNextScheduleName(afterSchedule.get(0).getStageName()); baseMapper.updateById(contract); } //只有当前合同签字阶段 if(ArrayUtil.isEmpty(afterSchedule.toArray())){ fitstSchedule.setEffectiveDate(DateUtil.offsetDay(contract.getSignDate(),fitstSchedule.getAgreedDays())); fitstSchedule.setEffectiveEndDate(contract.getExpirationDate()); contractPaymentScheduleMapper.updateById(fitstSchedule); } } @Override public R genCurrentOverdue() { List scheduleList = contractPaymentScheduleMapper.selectList(Wrappers.lambdaQuery() .lt(ContractPaymentSchedule::getEffectiveEndDate, DateUtil.today()) .ne(ContractPaymentSchedule::getPaymentStatus,"2")); if (ArrayUtil.isNotEmpty(scheduleList.toArray())){ scheduleList.stream().forEach(contractPaymentSchedule -> { Contract contract = baseMapper.selectById(contractPaymentSchedule.getContractId()); //应收超期 PaymentConfirm overdueConfirm = new PaymentConfirm(); overdueConfirm.setBusinessType("应收超期"); overdueConfirm.setBusGuestId(contract.getPartyAId()); overdueConfirm.setBusGuestName(contract.getPartyA()); overdueConfirm.setContractId(contract.getId()); overdueConfirm.setContractName(contract.getContractName()); overdueConfirm.setContractNo(contract.getContractNo()); overdueConfirm.setConfirmTime(new Date()); overdueConfirm.setScheduleId(contractPaymentSchedule.getId()); overdueConfirm.setScheduleName(contractPaymentSchedule.getStageName()); PaymentConfirm newLastConfirm = paymentConfirmMapper.selectOne(Wrappers.lambdaQuery().eq(PaymentConfirm::getContractId,contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); overdueConfirm.setTransationAmount(StrUtil.equals(contractPaymentSchedule.getPaymentStatus()+"","0")? contractPaymentSchedule.getPlannedAmount(): contractPaymentSchedule.getPlannedAmount().subtract(contractPaymentSchedule.getActualAmount())); overdueConfirm.setReceivableAmount(newLastConfirm.getTotalAmount().multiply(new BigDecimal("-1"))); overdueConfirm.setOverdueAmount(overdueConfirm.getTransationAmount()); overdueConfirm.setTotalAmount(newLastConfirm.getTotalAmount()); overdueConfirm.setCompId(contract.getCompId()); //判断当前阶段是否已生成上阶段应收超期 PaymentConfirm oiverdueConfirm = paymentConfirmMapper.selectOne(Wrappers.lambdaQuery().eq(PaymentConfirm::getScheduleId, contractPaymentSchedule.getId()) .eq(PaymentConfirm::getBusinessType, "应收超期")); if (ObjUtil.isNull(oiverdueConfirm)) { overdueConfirm.setCompId(contractPaymentSchedule.getCompId()); paymentConfirmMapper.insert(overdueConfirm); } //当前逾期 CurrentOverdue currentOverdue = new CurrentOverdue(); currentOverdue.setBusGuestId(contract.getPartyAId()); currentOverdue.setBusGuestName(contract.getPartyA()); currentOverdue.setContractId(contractPaymentSchedule.getContractId()); currentOverdue.setContractName(contractPaymentSchedule.getContractName()); currentOverdue.setScheduleId(contractPaymentSchedule.getId()); currentOverdue.setScheduleName(contractPaymentSchedule.getStageName()); currentOverdue.setCompId(contract.getCompId()); currentOverdue.setContractExpirTime(contractPaymentSchedule.getEffectiveEndDate()); currentOverdue.setReceivableAmount(StrUtil.equals(contractPaymentSchedule.getPaymentStatus()+"","0")? contractPaymentSchedule.getPlannedAmount():contractPaymentSchedule.getPlannedAmount().subtract(contractPaymentSchedule.getActualAmount())); currentOverdue.setOverdueDuration(BigDecimal.valueOf(DateUtil.betweenDay(contractPaymentSchedule.getEffectiveEndDate(),new Date(),true))); CurrentOverdue overdue = currentOverdueMapper.selectOne(Wrappers.lambdaQuery().eq(CurrentOverdue::getContractId,currentOverdue.getContractId()) .eq(CurrentOverdue::getScheduleId,currentOverdue.getScheduleId()).last("limit 1")); if (ObjUtil.isNull(overdue)){ currentOverdue.setCompId(contractPaymentSchedule.getCompId()); currentOverdueMapper.insert(currentOverdue); }else { overdue.setOverdueDuration(BigDecimal.valueOf(DateUtil.betweenDay(contractPaymentSchedule.getEffectiveEndDate(),new Date(),true))); currentOverdueMapper.updateById(overdue); } }); } return R.ok(); } }