package com.ruoyi.production.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.security.LoginUser; import com.ruoyi.production.dto.*; import com.ruoyi.production.mapper.SalesLedgerSchedulingMapper; import com.ruoyi.production.mapper.SalesLedgerWorkMapper; import com.ruoyi.production.mapper.SpeculativeTradingInfoMapper; import com.ruoyi.production.pojo.SalesLedgerScheduling; import com.ruoyi.production.pojo.SalesLedgerWork; import com.ruoyi.production.pojo.SpeculativeTradingInfo; import com.ruoyi.production.service.SalesLedgerSchedulingService; import com.ruoyi.project.system.domain.SysUser; import com.ruoyi.project.system.mapper.SysUserMapper; import com.ruoyi.sales.mapper.LossMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.pojo.Loss; import com.ruoyi.sales.pojo.SalesLedgerProduct; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.BeanUtils; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.math.RoundingMode; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; /** * @author :yys * @date : 2025/7/21 14:41 */ @Service @RequiredArgsConstructor @Slf4j public class SalesLedgerSchedulingServiceImpl extends ServiceImpl implements SalesLedgerSchedulingService { private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper; private final SalesLedgerWorkMapper salesLedgerWorkMapper; @Override public IPage listPage(Page page, SalesLedgerSchedulingDto salesLedgerSchedulingDto) { IPage list = salesLedgerSchedulingMapper.listPage(page, salesLedgerSchedulingDto); if(list.getTotal() == 0){ return list; } Set collect = list.getRecords().stream().map(SalesLedgerSchedulingDto::getSalesLedgerProductId).collect(Collectors.toSet()); LambdaQueryWrapper salesLedgerWorkLambdaQueryWrapper = new LambdaQueryWrapper<>(); salesLedgerWorkLambdaQueryWrapper.in(SalesLedgerWork::getSalesLedgerProductId, collect) .ne(SalesLedgerWork::getStatus, 1); List salesLedgerWorks = salesLedgerWorkMapper.selectList(salesLedgerWorkLambdaQueryWrapper); list.getRecords().forEach(i -> { // 获取完成数量 i.setSuccessNum(salesLedgerWorks .stream() .filter(j -> j.getSalesLedgerProductId().equals(i.getSalesLedgerProductId())) .map(SalesLedgerWork::getFinishedNum) .reduce(BigDecimal.ZERO, BigDecimal::add)); // 状态 = 数量和完工数量比较 if(i.getSchedulingNum().compareTo(new BigDecimal(0)) == 0){ i.setStatus("未完成"); } else if(i.getSchedulingNum().compareTo(i.getSuccessNum()) == 0){ i.setStatus("已完成"); }else{ i.setStatus("生产中"); } // 计算生产总量 = 规格 * 数量 / 1000 String[] split = i.getSpecificationModel().split("\\*"); if(split.length == 2){ BigDecimal multiply = new BigDecimal(split[0]) .multiply(new BigDecimal(split[1]) .multiply(i.getQuantity()).divide(new BigDecimal(1000),2, RoundingMode.CEILING)); i.setTotalProduction(multiply); } }); return list; } @Override public void export(HttpServletResponse response) { List list = salesLedgerSchedulingMapper.list(); if(CollectionUtils.isEmpty(list)){ throw new RuntimeException("无导出数据"); } Set collect = list.stream().map(SalesLedgerSchedulingDto::getSalesLedgerProductId).collect(Collectors.toSet()); LambdaQueryWrapper salesLedgerWorkLambdaQueryWrapper = new LambdaQueryWrapper<>(); salesLedgerWorkLambdaQueryWrapper.in(SalesLedgerWork::getSalesLedgerProductId, collect) .ne(SalesLedgerWork::getStatus, 1); List salesLedgerWorks = salesLedgerWorkMapper.selectList(salesLedgerWorkLambdaQueryWrapper); list.forEach(i -> { // 获取完成数量 i.setSuccessNum(salesLedgerWorks .stream() .filter(j -> j.getSalesLedgerProductId().equals(i.getSalesLedgerProductId())) .map(SalesLedgerWork::getFinishedNum) .reduce(BigDecimal.ZERO, BigDecimal::add)); }); ExcelUtil util = new ExcelUtil<>(SalesLedgerSchedulingDto.class); util.exportExcel(response, list, "生产订单"); } private final SysUserMapper sysUserMapper; private final SpeculativeTradingInfoMapper speculativeTradingInfoMapper; @Override public String productionDispatch(List productionDispatchAddDtoList) { int i = 0; int successNum = 0; LoginUser loginUser = SecurityUtils.getLoginUser(); for (ProductionDispatchAddDto productionDispatchAddDto : productionDispatchAddDtoList) { SysUser sysUser = sysUserMapper.selectUserById(productionDispatchAddDto.getSchedulingUserId() == null ? loginUser.getUser().getUserId() : productionDispatchAddDto.getSchedulingUserId()); if(sysUser == null){ i++; continue; } // 获取空余炒机 String[] split = productionDispatchAddDto.getSpeculativeTradingName().split(","); if(split != null && split.length == 0){ i++; continue; } List speculativeTradingInfos = speculativeTradingInfoMapper.selectList(new LambdaQueryWrapper() .in(SpeculativeTradingInfo::getName, Arrays.asList(split)) .orderByAsc(SpeculativeTradingInfo::getSort)); if(CollectionUtils.isEmpty(speculativeTradingInfos)){ i++; continue; } AtomicReference name = new AtomicReference<>(""); //需要绑定的炒机 //通过规格型号和排产数量计算本次生产产量 String[] split1 = productionDispatchAddDto.getSpecificationModel().split("\\*"); if(split1.length != 2){ i++; continue; } // 本次生产产量 BigDecimal productionNum = new BigDecimal(split1[0]) .multiply(new BigDecimal(split1[1]).multiply(productionDispatchAddDto.getSchedulingNum())); // 多个炒机情况 if(speculativeTradingInfos.size() > 1){ for (SpeculativeTradingInfo speculativeTradingInfo : speculativeTradingInfos) { // 获取该炒机正在排产量 BigDecimal schedulingNumBySpeculativeTradingName = getSchedulingNumBySpeculativeTradingName(speculativeTradingInfo.getName()); // 如果该炒机总量(单位kg需要乘1000) - 正在排产量 >=本次生产产量就分配此炒机 if(speculativeTradingInfo.getWorkLoad().multiply(new BigDecimal(1000)).subtract(schedulingNumBySpeculativeTradingName).compareTo(productionNum) >= 0){ name.set(speculativeTradingInfo.getName()); break; } } }else{ // 单个炒机情况 name.set(speculativeTradingInfos.get(0).getName()); } if(name.get().isEmpty()){ i++; continue; } SalesLedgerScheduling salesLedgerScheduling = SalesLedgerScheduling.builder() .salesLedgerId(productionDispatchAddDto.getSalesLedgerId()) .salesLedgerProductId(productionDispatchAddDto.getSalesLedgerProductId()) .speculativeTradingName(name.get()) .schedulingUserId(sysUser.getUserId()) .schedulingUserName(sysUser.getNickName()) .schedulingNum(productionDispatchAddDto.getSchedulingNum()) .schedulingDate(productionDispatchAddDto.getSchedulingDate() == null ? LocalDate.now() : LocalDate.parse(productionDispatchAddDto.getSchedulingDate(), DateTimeFormatter.ofPattern("yyyy-MM-dd"))) .status(1) .build(); salesLedgerSchedulingMapper.insert(salesLedgerScheduling); successNum++; } return "派工成功数量" + successNum + ",失败数量" + i; } private final SalesLedgerProductMapper salesLedgerProductMapper; /** *通过炒机名称获取当天正在排产量 * @return */ public BigDecimal getSchedulingNumBySpeculativeTradingName(String speculativeTradingName){ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(SalesLedgerScheduling::getSpeculativeTradingName, speculativeTradingName) .eq(SalesLedgerScheduling::getSchedulingDate, LocalDate.now()); List salesLedgerSchedulings = salesLedgerSchedulingMapper.selectList(queryWrapper); if(CollectionUtils.isEmpty(salesLedgerSchedulings)){ return BigDecimal.ZERO; } List collect = salesLedgerSchedulings.stream().map(SalesLedgerScheduling::getSalesLedgerProductId).collect(Collectors.toList()); List salesLedgerProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper() .in(SalesLedgerProduct::getId, collect)); if(CollectionUtils.isEmpty(salesLedgerProducts)) return BigDecimal.ZERO; AtomicInteger totalNum = new AtomicInteger(0); //总数 salesLedgerSchedulings.forEach(item ->{ List collect1 = salesLedgerProducts.stream() .filter(j -> j.getId().equals(item.getSalesLedgerProductId())) .collect(Collectors.toList()); if(!CollectionUtils.isEmpty(collect1)){ SalesLedgerProduct salesLedgerProduct = collect1.get(0); // 根据产品规格 * 排产数量 获取本次生产产量并累计 String[] split = salesLedgerProduct.getSpecificationModel().split("\\*"); BigDecimal productionNum = new BigDecimal(split[0]) .multiply(new BigDecimal(split[1]).multiply(item.getSchedulingNum())); totalNum.addAndGet(productionNum.intValue()); } }); // 需要 / 损耗率 Loss loss = lossMapper.selectOne(new LambdaQueryWrapper().last("limit 1")); BigDecimal lossNum = loss == null ? new BigDecimal(6) : loss.getRate(); //没有损耗率则默认为6 return new BigDecimal(totalNum.get()).multiply(new BigDecimal(100)).divide(lossNum, 2,RoundingMode.HALF_UP); } private LossMapper lossMapper; /** *通过批量炒机名称获取当天正在排产量 * @return */ public BigDecimal getSchedulingNumBySpeculativeTradingNameList(List speculativeTradingName){ LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.in(SalesLedgerScheduling::getSpeculativeTradingName, speculativeTradingName) .eq(SalesLedgerScheduling::getSchedulingDate, LocalDate.now()); List salesLedgerSchedulings = salesLedgerSchedulingMapper.selectList(queryWrapper); if(CollectionUtils.isEmpty(salesLedgerSchedulings)){ return BigDecimal.ZERO; } List collect = salesLedgerSchedulings.stream().map(SalesLedgerScheduling::getSalesLedgerProductId).collect(Collectors.toList()); List salesLedgerProducts = salesLedgerProductMapper.selectList(new LambdaQueryWrapper() .in(SalesLedgerProduct::getId, collect)); if(CollectionUtils.isEmpty(salesLedgerProducts)) return BigDecimal.ZERO; AtomicInteger totalNum = new AtomicInteger(0); //总数 salesLedgerSchedulings.forEach(item ->{ List collect1 = salesLedgerProducts.stream() .filter(j -> j.getId().equals(item.getSalesLedgerProductId())) .collect(Collectors.toList()); if(!CollectionUtils.isEmpty(collect1)){ SalesLedgerProduct salesLedgerProduct = collect1.get(0); // 根据产品规格 * 排产数量 获取本次生产产量并累计 String[] split = salesLedgerProduct.getSpecificationModel().split("\\*"); BigDecimal productionNum = new BigDecimal(split[0]) .multiply(new BigDecimal(split[1]).multiply(item.getSchedulingNum())); totalNum.addAndGet(productionNum.intValue()); } }); return new BigDecimal(totalNum.get()); } @Override public IPage listPageProcess(Page page, SalesLedgerSchedulingProcessDto salesLedgerSchedulingDto) { IPage list = salesLedgerSchedulingMapper.listPageProcess(page, salesLedgerSchedulingDto); // Set collect = list.getRecords().stream().map(SalesLedgerSchedulingProcessDto::getId).collect(Collectors.toSet()); // if(CollectionUtils.isEmpty(collect)) return list; // LambdaQueryWrapper salesLedgerWorkLambdaQueryWrapper = new LambdaQueryWrapper<>(); // salesLedgerWorkLambdaQueryWrapper.in(SalesLedgerWork::getSalesLedgerSchedulingId, collect) // .ne(SalesLedgerWork::getStatus, 1); // List salesLedgerWorks = salesLedgerWorkMapper.selectList(salesLedgerWorkLambdaQueryWrapper); list.getRecords().forEach(i -> { // 计算生产总量 = 规格 * 数量 / 1000 String[] split = i.getSpecificationModel().split("\\*"); if(split.length == 2){ BigDecimal multiply = new BigDecimal(split[0]) .multiply(new BigDecimal(split[1]) .multiply(i.getSuccessNum()).divide(new BigDecimal(1000),2, RoundingMode.CEILING)); i.setTotalProduction(multiply); } }); return list; } @Override public int productionDispatchDelete(List ids) { LambdaQueryWrapper salesLedgerSchedulingLambdaQueryWrapper = new LambdaQueryWrapper(); salesLedgerSchedulingLambdaQueryWrapper.in(SalesLedgerScheduling::getId, ids); List salesLedgerSchedulings = salesLedgerSchedulingMapper.selectList(salesLedgerSchedulingLambdaQueryWrapper); if(CollectionUtils.isEmpty(salesLedgerSchedulings)) throw new RuntimeException("排产不存在"); List collect = salesLedgerSchedulings.stream().filter(i -> !i.getStatus().equals(1)).collect(Collectors.toList()); if(!CollectionUtils.isEmpty(collect)) throw new RuntimeException("排产已开始,请勿删除"); salesLedgerSchedulingMapper.deleteBatchIds(ids); return 0; } @Override public int processScheduling(List processSchedulingDtos) { for (ProcessSchedulingDto processSchedulingDto : processSchedulingDtos) { SalesLedgerScheduling salesLedgerScheduling = salesLedgerSchedulingMapper.selectById(processSchedulingDto.getId()); if(salesLedgerScheduling == null) throw new RuntimeException("排产不存在"); if(salesLedgerScheduling.getStatus().equals(3)) throw new RuntimeException("排产已完成,请勿重复排产"); SysUser sysUser = sysUserMapper.selectUserById(processSchedulingDto.getSchedulingUserId()); if(sysUser == null) throw new RuntimeException("排产人不存在"); salesLedgerScheduling.setFinishedNum(salesLedgerScheduling.getFinishedNum().add(processSchedulingDto.getSchedulingNum())); // LambdaQueryWrapper salesLedgerWorkLambdaQueryWrapper = new LambdaQueryWrapper<>(); // salesLedgerWorkLambdaQueryWrapper.eq(SalesLedgerWork::getSalesLedgerSchedulingId, salesLedgerScheduling.getId()) // .ne(SalesLedgerWork::getStatus, 1); // List salesLedgerWorks = salesLedgerWorkMapper.selectList(salesLedgerWorkLambdaQueryWrapper); if(salesLedgerScheduling.getSchedulingNum().compareTo(salesLedgerScheduling.getFinishedNum()) < 0){ throw new RuntimeException("当前排产数量大于待排产数量,请仔细核对!"); } if(salesLedgerScheduling.getSchedulingNum().compareTo(salesLedgerScheduling.getFinishedNum()) == 0){ salesLedgerScheduling.setStatus(3); }else{ salesLedgerScheduling.setStatus(2); } salesLedgerSchedulingMapper.updateById(salesLedgerScheduling); SalesLedgerWork.SalesLedgerWorkBuilder salesLedgerWorkBuilder = SalesLedgerWork.builder() .salesLedgerSchedulingId(salesLedgerScheduling.getId()) .salesLedgerId(salesLedgerScheduling.getSalesLedgerId()) .remark(processSchedulingDto.getRemark()) .type(processSchedulingDto.getType()) .loss(processSchedulingDto.getLoss()) .receive(processSchedulingDto.getReceive()) .salesLedgerProductId(salesLedgerScheduling.getSalesLedgerProductId()) .schedulingUserId(salesLedgerScheduling.getSchedulingUserId()) .schedulingUserName(sysUser.getNickName()) .schedulingNum(processSchedulingDto.getSchedulingNum()) .workHours(processSchedulingDto.getWorkHours()) .process(processSchedulingDto.getProcess()) .status(1) .schedulingDate(LocalDate.parse(processSchedulingDto.getSchedulingDate(), DateTimeFormatter.ISO_LOCAL_DATE)); salesLedgerWorkMapper.insert(salesLedgerWorkBuilder.build()); } return 0; } @Override public void exportOne(HttpServletResponse response) { List list = salesLedgerSchedulingMapper.list(); if(CollectionUtils.isEmpty(list)){ throw new RuntimeException("无导出数据"); } List dais = new ArrayList<>(); list.forEach(i -> { DaiDto daiDto = new DaiDto(); BeanUtils.copyProperties(i, daiDto); // 获取待排产数量 daiDto.setDaiNum(daiDto.getQuantity().subtract(i.getSchedulingNum())); dais.add(daiDto); }); ExcelUtil util = new ExcelUtil<>(DaiDto.class); util.exportExcel(response, dais, "生产派工"); } }