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.dto.OutBoundAddDTO; import com.by4cloud.platformx.business.dto.OutSubjectMatterAddDTO; import com.by4cloud.platformx.business.entity.*; import com.by4cloud.platformx.business.mapper.*; import com.by4cloud.platformx.business.service.OutBoundService; import com.by4cloud.platformx.common.core.util.R; 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.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * EPR出库记录 * * @author syt * @date 2026-04-29 11:32:05 */ @Service @RequiredArgsConstructor public class OutBoundServiceImpl extends ServiceImpl implements OutBoundService { private final ContractPaymentScheduleMapper scheduleMapper; private final ContractSubjectMatterMapper contractSubjectMatterMapper; private final PaymentConfirmMapper paymentConfirmMapper; private final ContractMapper contractMapper; private final ContractPaymentScheduleProcessMapper scheduleProcessMapper; @Override public R add(OutBoundAddDTO addDTO) { if (ArrayUtil.isEmpty(addDTO.getSubjectMatterList().toArray())) { return R.failed("出库标的物不能为空"); } MPJLambdaWrapper wrapper = new MPJLambdaWrapper() .selectAll(ContractSubjectMatter.class) .ne(ContractSubjectMatter::getDeliveryStatus, 2) .exists(Contract.class, contractQuery -> contractQuery.select(ContractSubjectMatter::getId) .eq(Contract::getId, ContractSubjectMatter::getContractId) .eq(StrUtil.isNotBlank(addDTO.getBusGuestName()), Contract::getPartyA, addDTO.getBusGuestName()) .eq(ObjUtil.isNotNull(addDTO.getBusGuestId()), Contract::getPartyAId, addDTO.getBusGuestId()) ) .orderByAsc(ContractSubjectMatter::getCreateTime); List subjectMatterList = contractSubjectMatterMapper.selectList(wrapper); if (ArrayUtil.isEmpty(subjectMatterList.toArray())) { return R.failed("没有查询到相关合同订单"); } Double outTotal = subjectMatterList.stream().mapToDouble(item -> { // 优先判断 remainNum if (item.getRemainingQuantity() != null && item.getRemainingQuantity().compareTo(new BigDecimal("0")) > 0) { return item.getRemainingQuantity().doubleValue(); } else { // remainNum 为 null 或 0 时,使用 quantity return item.getQuantity() == null ? 0.0 : item.getQuantity().doubleValue(); } }).sum(); BigDecimal orderNum = addDTO.getSubjectMatterList().stream().map(OutSubjectMatterAddDTO::getOutBoundNum) .filter(num -> num != null) // 过滤掉 null 值,防止 NullPointerException .reduce(BigDecimal.ZERO, BigDecimal::add); if (new BigDecimal(outTotal).compareTo(orderNum) < 0) { return R.failed("出库数量超出合同订单数量"); } //当前入库标的物 List currentOutList = new ArrayList<>(); addDTO.getSubjectMatterList().stream().forEach(outSubjectMatterAddDTO -> { BigDecimal remainNum = outSubjectMatterAddDTO.getOutBoundNum(); for (ContractSubjectMatter subjectMatter : subjectMatterList) { if (subjectMatter.getDeliveredQuantity().compareTo(new BigDecimal("0")) > 0) { remainNum = remainNum.subtract(subjectMatter.getRemainingQuantity()); //部分交付状态下 全部出库 if (remainNum.compareTo(new BigDecimal("0")) >= 0) { BigDecimal currentOut = subjectMatter.getRemainingQuantity(); subjectMatter.setDeliveredQuantity(subjectMatter.getQuantity()); subjectMatter.setRemainingQuantity(new BigDecimal("0")); subjectMatter.setActualDeliveryDate(DateUtil.today()); subjectMatter.setDeliveryStatus(2); subjectMatter.setLastDeliveredQuantity(currentOut); contractSubjectMatterMapper.updateById(subjectMatter); currentOutList.add(subjectMatter); } else { BigDecimal currentOut = remainNum.add(subjectMatter.getRemainingQuantity()); subjectMatter.setDeliveredQuantity(subjectMatter.getQuantity().add(remainNum)); subjectMatter.setRemainingQuantity(remainNum.multiply(new BigDecimal("-1"))); subjectMatter.setActualDeliveryDate(DateUtil.today()); subjectMatter.setDeliveryStatus(1); subjectMatter.setLastDeliveredQuantity(currentOut); contractSubjectMatterMapper.updateById(subjectMatter); currentOutList.add(subjectMatter); break; } } else { //未交付状态下 remainNum = remainNum.subtract(subjectMatter.getQuantity()); if (remainNum.compareTo(new BigDecimal("0")) >= 0) { subjectMatter.setDeliveredQuantity(subjectMatter.getQuantity()); subjectMatter.setRemainingQuantity(new BigDecimal("0")); subjectMatter.setActualDeliveryDate(DateUtil.today()); subjectMatter.setDeliveryStatus(2); contractSubjectMatterMapper.updateById(subjectMatter); subjectMatter.setLastDeliveredQuantity(subjectMatter.getQuantity()); currentOutList.add(subjectMatter); } else { BigDecimal currentOut = remainNum.add(subjectMatter.getQuantity()); subjectMatter.setDeliveredQuantity(subjectMatter.getQuantity().add(remainNum)); subjectMatter.setRemainingQuantity(remainNum.multiply(new BigDecimal("-1"))); subjectMatter.setActualDeliveryDate(DateUtil.today()); subjectMatter.setDeliveryStatus(1); subjectMatter.setLastDeliveredQuantity(currentOut); contractSubjectMatterMapper.updateById(subjectMatter); currentOutList.add(subjectMatter); break; } } } OutBound outBound = BeanUtil.copyProperties(outSubjectMatterAddDTO, OutBound.class); outBound.setBusGuestName(addDTO.getBusGuestName()); outBound.setBusGuestId(addDTO.getBusGuestId()); outBound.setOutBoundTime(addDTO.getOutBoundTime()); baseMapper.insert(outBound); }); //出库应收款明细 if (ArrayUtil.isNotEmpty(currentOutList.toArray())) { //根据合同id拆分应收明细 Map> conSubMatMap = currentOutList.stream().collect(Collectors.groupingBy(ContractSubjectMatter::getContractId)); conSubMatMap.forEach((key, value) -> { //查询合同是否有出库阶段 ContractPaymentSchedule schedule = scheduleMapper.selectOne(Wrappers.lambdaQuery().eq(ContractPaymentSchedule::getContractId, key) .eq(ContractPaymentSchedule::getStageName, "发货前")); //当前出库金额 BigDecimal outPirce = value.stream() .filter(item -> item.getLastDeliveredQuantity() != null && item.getUnitPrice() != null) .map(item -> item.getLastDeliveredQuantity().multiply(item.getUnitPrice())) .reduce(BigDecimal.ZERO, BigDecimal::add); //合同金额 Contract contract = contractMapper.selectById(key); //出库是否完成 if (outPirce.compareTo(contract.getAmount())<0){ contract.setBillingStatus("1"); contractMapper.updateById(contract); } if (outPirce.compareTo(contract.getAmount())==0){ contract.setBillingStatus("2"); contractMapper.updateById(contract); } if (ObjUtil.isNotNull(schedule)) { //按出库资金比例 计算发货前应收更新资金明细 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(schedule.getId()); paymentConfirm.setScheduleName(schedule.getStageName()); paymentConfirm.setConfirmTime(addDTO.getOutBoundTime()); paymentConfirm.setTransationAmount(outPirce.divide(contract.getAmount(), 10, RoundingMode.HALF_UP).multiply(schedule.getPlannedAmount())); paymentConfirm.setReceivableAmount(paymentConfirm.getTransationAmount()); paymentConfirm.setTotalAmount(paymentConfirm.getTransationAmount().multiply(new BigDecimal("-1"))); //最近应收 PaymentConfirm lastConfirm = paymentConfirmMapper.selectOne(Wrappers.lambdaQuery().eq(PaymentConfirm::getContractId, contract.getId()) .orderByDesc(PaymentConfirm::getCreateTime).last("limit 1")); if (ObjUtil.isNotNull(lastConfirm)) { paymentConfirm.setTotalAmount(paymentConfirm.getTotalAmount().add(lastConfirm.getTotalAmount())); paymentConfirmMapper.insert(paymentConfirm); } else { paymentConfirmMapper.insert(paymentConfirm); } //更新发货前收款生效时间 if (ObjUtil.isNull(schedule.getEffectiveDate())){ schedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getOutBoundTime(),schedule.getAgreedDays())); //查询是否有后续阶段 List afterSchedule = scheduleMapper.selectList(Wrappers.lambdaQuery().eq(ContractPaymentSchedule::getContractId, key) .gt(ContractPaymentSchedule::getStageOrder, schedule.getStageOrder())); if (ArrayUtil.isEmpty(afterSchedule.toArray())){ schedule.setEffectiveEndDate(contract.getExpirationDate()); } scheduleMapper.updateById(schedule); //查询是否有之前阶段 ContractPaymentSchedule beforeSchedule = scheduleMapper.selectOne(Wrappers.lambdaQuery().eq(ContractPaymentSchedule::getContractId, schedule.getContractId()) .lt(ContractPaymentSchedule::getStageOrder, schedule.getStageOrder()).orderByDesc(ContractPaymentSchedule::getCreateTime).last("limit 1")); if (ObjUtil.isNotNull(beforeSchedule)){ beforeSchedule.setEffectiveEndDate(DateUtil.offsetDay(addDTO.getOutBoundTime(),beforeSchedule.getAgreedDays())); scheduleMapper.updateById(beforeSchedule); } } //更新履约 ContractPaymentScheduleProcess contractPaymentScheduleProcess = new ContractPaymentScheduleProcess(); contractPaymentScheduleProcess.setContractId(schedule.getContractId()); contractPaymentScheduleProcess.setContractName(schedule.getContractName()); contractPaymentScheduleProcess.setScheduleId(schedule.getId()); contractPaymentScheduleProcess.setScheduleName(schedule.getStageName()); contractPaymentScheduleProcess.setProcessDate(addDTO.getOutBoundTime()); scheduleProcessMapper.insert(contractPaymentScheduleProcess); //查询是否有后续阶段 List afterSchedule = scheduleMapper.selectList(Wrappers.lambdaQuery() .eq(ContractPaymentSchedule::getContractId, schedule.getContractId()) .gt(ContractPaymentSchedule::getStageOrder, schedule.getStageOrder())); if (ArrayUtil.isNotEmpty(afterSchedule.toArray())&&afterSchedule.size()==1){ //最后阶段生效时间 ContractPaymentSchedule endSchedule = afterSchedule.get(0); endSchedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getOutBoundTime(),endSchedule.getAgreedDays())); endSchedule.setEffectiveEndDate(contract.getExpirationDate()); scheduleMapper.updateById(endSchedule); //当前阶段生效时间 schedule.setEffectiveDate(DateUtil.offsetDay(addDTO.getOutBoundTime(),schedule.getAgreedDays())); schedule.setEffectiveEndDate(endSchedule.getEffectiveDate()); scheduleMapper.updateById(schedule); //最后阶段应收 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(schedule.getStageName()); newConfim.setConfirmTime(addDTO.getOutBoundTime()); 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); } if(ArrayUtil.isEmpty(afterSchedule.toArray())){ schedule.setEffectiveEndDate(contract.getExpirationDate()); scheduleMapper.updateById(schedule); } } }); } return R.ok(); } }